class.frame-nonce-preview.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. /**
  3. * Allows viewing posts on the frontend when the user is not logged in.
  4. */
  5. class Jetpack_Frame_Nonce_Preview {
  6. static $instance = null;
  7. /**
  8. * Returns the single instance of the Jetpack_Frame_Nonce_Preview object
  9. *
  10. * @since 4.3.0
  11. *
  12. * @return Jetpack_Frame_Nonce_Preview
  13. **/
  14. public static function get_instance() {
  15. if ( ! is_null( self::$instance ) ) {
  16. return self::$instance;
  17. }
  18. return self::$instance = new Jetpack_Frame_Nonce_Preview();
  19. }
  20. function __construct() {
  21. if ( isset( $_GET['frame-nonce'] ) && ! is_admin() ) {
  22. add_filter( 'pre_get_posts', array( $this, 'maybe_display_post' ) );
  23. }
  24. // autosave previews are validated differently
  25. if ( isset( $_GET[ 'frame-nonce' ] ) && isset( $_GET[ 'preview_id' ] ) && isset( $_GET[ 'preview_nonce' ] ) ) {
  26. remove_action( 'init', '_show_post_preview' );
  27. add_action( 'init', array( $this, 'handle_autosave_nonce_validation' ) );
  28. }
  29. }
  30. /**
  31. * Verify that frame nonce exists, and if so, validate the nonce by calling WP.com.
  32. *
  33. * @since 4.3.0
  34. *
  35. * @return bool
  36. */
  37. public function is_frame_nonce_valid() {
  38. if ( empty( $_GET[ 'frame-nonce' ] ) ) {
  39. return false;
  40. }
  41. Jetpack::load_xml_rpc_client();
  42. $xml = new Jetpack_IXR_Client();
  43. $xml->query( 'jetpack.verifyFrameNonce', sanitize_key( $_GET['frame-nonce'] ) );
  44. if ( $xml->isError() ) {
  45. return false;
  46. }
  47. return (bool) $xml->getResponse();
  48. }
  49. /**
  50. * Conditionally add a hook on posts_results if this is the main query, a preview, and singular.
  51. *
  52. * @since 4.3.0
  53. *
  54. * @param WP_Query $query
  55. *
  56. * @return WP_Query
  57. */
  58. public function maybe_display_post( $query ) {
  59. if (
  60. $query->is_main_query() &&
  61. $query->is_preview() &&
  62. $query->is_singular()
  63. ) {
  64. add_filter( 'posts_results', array( $this, 'set_post_to_publish' ), 10, 2 );
  65. }
  66. return $query;
  67. }
  68. /**
  69. * Conditionally set the first post to 'publish' if the frame nonce is valid and there is a post.
  70. *
  71. * @since 4.3.0
  72. *
  73. * @param array $posts
  74. *
  75. * @return array
  76. */
  77. public function set_post_to_publish( $posts ) {
  78. remove_filter( 'posts_results', array( $this, 'set_post_to_publish' ), 10, 2 );
  79. if ( empty( $posts ) || is_user_logged_in() || ! $this->is_frame_nonce_valid() ) {
  80. return $posts;
  81. }
  82. $posts[0]->post_status = 'publish';
  83. // Disable comments and pings for this post.
  84. add_filter( 'comments_open', '__return_false' );
  85. add_filter( 'pings_open', '__return_false' );
  86. return $posts;
  87. }
  88. /**
  89. * Handle validation for autosave preview request
  90. *
  91. * @since 4.7.0
  92. *
  93. */
  94. public function handle_autosave_nonce_validation() {
  95. if ( ! $this->is_frame_nonce_valid() ) {
  96. wp_die( __( 'Sorry, you are not allowed to preview drafts.', 'jetpack' ) );
  97. }
  98. add_filter( 'the_preview', '_set_preview' );
  99. }
  100. }
  101. Jetpack_Frame_Nonce_Preview::get_instance();