diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index 7b6072f2ec..d3f5fc18dd 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -388,7 +388,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { $page = (int) $query_args['paged']; $total_posts = $posts_query->found_posts; - if ( $total_posts < 1 ) { + if ( $total_posts < 1 && $page > 1 ) { // Out-of-bounds, run the query again without LIMIT for total count. unset( $query_args['paged'] ); diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 47ea5820f3..ec52dbcd0d 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -29,6 +29,11 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control */ private $test_file2; + /** + * @var array The recorded posts query clauses. + */ + protected $posts_clauses; + public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { self::$superadmin_id = $factory->user->create( array( @@ -85,6 +90,19 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control $orig_file2 = DIR_TESTDATA . '/images/codeispoetry.png'; $this->test_file2 = get_temp_dir() . 'codeispoetry.png'; copy( $orig_file2, $this->test_file2 ); + + add_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 ); + add_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 ); + } + + public function wpSetUpBeforeRequest( $result ) { + $this->posts_clauses = array(); + return $result; + } + + public function save_posts_clauses( $clauses ) { + $this->posts_clauses[] = $clauses; + return $clauses; } public function tear_down() { @@ -619,6 +637,48 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control $this->assertSame( $id2, $data[0]['id'] ); } + /** + * @ticket 55677 + */ + public function test_get_items_avoid_duplicated_count_query_if_no_items() { + $request = new WP_REST_Request( 'GET', '/wp/v2/media' ); + $request->set_param( 'media_type', 'video' ); + + $response = rest_get_server()->dispatch( $request ); + + $this->assertCount( 1, $this->posts_clauses ); + + $headers = $response->get_headers(); + + $this->assertSame( 0, $headers['X-WP-Total'] ); + $this->assertSame( 0, $headers['X-WP-TotalPages'] ); + } + + /** + * @ticket 55677 + */ + public function test_get_items_with_empty_page_runs_count_query_after() { + $this->factory->attachment->create_object( + $this->test_file, + 0, + array( + 'post_date' => '2022-06-12T00:00:00Z', + 'post_mime_type' => 'image/jpeg', + 'post_excerpt' => 'A sample caption', + ) + ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/media' ); + $request->set_param( 'media_type', 'image' ); + $request->set_param( 'page', 2 ); + + $response = rest_get_server()->dispatch( $request ); + + $this->assertCount( 2, $this->posts_clauses ); + + $this->assertErrorResponse( 'rest_post_invalid_page_number', $response, 400 ); + } + public function test_get_item() { $attachment_id = $this->factory->attachment->create_object( $this->test_file, diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index f02037962c..64d8ddbc90 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -1385,8 +1385,7 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te $response = rest_get_server()->dispatch( $request ); $this->assertCount( 0, $response->get_data() ); - // FIXME Since this request returns zero posts, the query is executed twice. - $this->assertCount( 2, $this->posts_clauses ); + $this->assertCount( 1, $this->posts_clauses ); $this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 ); $this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" ); @@ -1417,8 +1416,7 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te $response = rest_get_server()->dispatch( $request ); $this->assertCount( 0, $response->get_data() ); - // FIXME Since this request returns zero posts, the query is executed twice. - $this->assertCount( 2, $this->posts_clauses ); + $this->assertCount( 1, $this->posts_clauses ); $this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 ); $this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" ); @@ -1436,8 +1434,7 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te $response = rest_get_server()->dispatch( $request ); $this->assertCount( 0, $response->get_data() ); - // FIXME Since this request returns zero posts, the query is executed twice. - $this->assertCount( 2, $this->posts_clauses ); + $this->assertCount( 1, $this->posts_clauses ); $this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 ); $this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );