From 5e8563eb6bf26dd1b299700206405246e7bf1372 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Wed, 5 Feb 2020 01:31:38 +0000 Subject: [PATCH] Posts, Post Types: Fail gracefully when checking whether a single post with an unregistered post status should be displayed in `WP_Query::get_posts()`. If the post status is not registered, assume it's not public, but still allow access to users with edit permissions (same as for a protected post status, e.g. `draft`), so that they could recover orphaned content. Add unit tests. Follow-up to [47178]. Props roytanck, SergeyBiryukov. Fixes #48653. git-svn-id: https://develop.svn.wordpress.org/trunk@47181 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-query.php | 48 +++++++++++--------- tests/phpunit/tests/query/postStatus.php | 56 ++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 7233e2ba87..38df928f08 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -3066,35 +3066,43 @@ class WP_Query { // Check post status to determine if post should be displayed. if ( ! empty( $this->posts ) && ( $this->is_single || $this->is_page ) ) { $status = get_post_status( $this->posts[0] ); + if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) { $this->is_page = false; $this->is_single = true; $this->is_attachment = true; } - $post_status_obj = get_post_status_object( $status ); // If the post_status was specifically requested, let it pass through. - if ( ! $post_status_obj->public && ! in_array( $status, $q_status ) ) { + if ( ! in_array( $status, $q_status ) ) { + $post_status_obj = get_post_status_object( $status ); - if ( ! is_user_logged_in() ) { - // User must be logged in to view unpublished posts. - $this->posts = array(); - } else { - if ( $post_status_obj->protected ) { - // User must have edit permissions on the draft to preview. - if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) { - $this->posts = array(); - } else { - $this->is_preview = true; - if ( 'future' != $status ) { - $this->posts[0]->post_date = current_time( 'mysql' ); - } - } - } elseif ( $post_status_obj->private ) { - if ( ! current_user_can( $read_cap, $this->posts[0]->ID ) ) { - $this->posts = array(); - } + if ( $post_status_obj && ! $post_status_obj->public ) { + if ( ! is_user_logged_in() ) { + // User must be logged in to view unpublished posts. + $this->posts = array(); } else { + if ( $post_status_obj->protected ) { + // User must have edit permissions on the draft to preview. + if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) { + $this->posts = array(); + } else { + $this->is_preview = true; + if ( 'future' != $status ) { + $this->posts[0]->post_date = current_time( 'mysql' ); + } + } + } elseif ( $post_status_obj->private ) { + if ( ! current_user_can( $read_cap, $this->posts[0]->ID ) ) { + $this->posts = array(); + } + } else { + $this->posts = array(); + } + } + } elseif ( ! $post_status_obj ) { + // Post status is not registered, assume it's not public. + if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) { $this->posts = array(); } } diff --git a/tests/phpunit/tests/query/postStatus.php b/tests/phpunit/tests/query/postStatus.php index d907925907..0ba6b98e67 100644 --- a/tests/phpunit/tests/query/postStatus.php +++ b/tests/phpunit/tests/query/postStatus.php @@ -262,6 +262,27 @@ class Tests_Query_PostStatus extends WP_UnitTestCase { $this->assertEmpty( $q->posts ); } + public function test_single_post_with_nonpublic_status_should_not_be_shown_for_any_user() { + register_post_type( 'foo_pt' ); + register_post_status( 'foo_ps', array( 'public' => false ) ); + $p = self::factory()->post->create( + array( + 'post_status' => 'foo_ps', + 'post_author' => self::$author_user_id, + ) + ); + + wp_set_current_user( self::$editor_user_id ); + + $q = new WP_Query( + array( + 'p' => $p, + ) + ); + + $this->assertEmpty( $q->posts ); + } + public function test_single_post_with_nonpublic_and_protected_status_should_not_be_shown_for_user_who_cannot_edit_others_posts() { register_post_type( 'foo_pt' ); register_post_status( @@ -370,15 +391,44 @@ class Tests_Query_PostStatus extends WP_UnitTestCase { $this->assertEquals( array( $p ), wp_list_pluck( $q->posts, 'ID' ) ); } - public function test_single_post_with_nonpublic_and_protected_status_should_not_be_shown_for_any_user() { + /** + * @ticket 48653 + */ + public function test_single_post_with_nonexisting_status_should_not_be_shown_for_user_who_cannot_edit_others_posts() { register_post_type( 'foo_pt' ); - register_post_status( 'foo_ps', array( 'public' => false ) ); + register_post_status( 'foo_ps', array( 'public' => true ) ); + $p = self::factory()->post->create( + array( + 'post_status' => 'foo_ps', + 'post_author' => self::$editor_user_id, + ) + ); + _unregister_post_status( 'foo_ps' ); + + wp_set_current_user( self::$author_user_id ); + + $q = new WP_Query( + array( + 'p' => $p, + ) + ); + + $this->assertEmpty( $q->posts ); + } + + /** + * @ticket 48653 + */ + public function test_single_post_with_nonexisting_status_should_be_shown_for_user_who_can_edit_others_posts() { + register_post_type( 'foo_pt' ); + register_post_status( 'foo_ps', array( 'public' => true ) ); $p = self::factory()->post->create( array( 'post_status' => 'foo_ps', 'post_author' => self::$author_user_id, ) ); + _unregister_post_status( 'foo_ps' ); wp_set_current_user( self::$editor_user_id ); @@ -388,7 +438,7 @@ class Tests_Query_PostStatus extends WP_UnitTestCase { ) ); - $this->assertEmpty( $q->posts ); + $this->assertEquals( array( $p ), wp_list_pluck( $q->posts, 'ID' ) ); } /**