Make WordPress Core


Ignore:
Timestamp:
02/25/2017 05:02:17 AM (9 years ago)
Author:
jnylen0
Message:

REST API: Fix behavior of sticky posts filter when no posts are sticky.

Previously, when getting posts from the API with sticky=true, if there were no sticky posts set, the query would return all posts as if the sticky argument was not set. In this situation, the query should return an empty array instead.

A sticky=true query that should return an empty array (in the previous situation, or with include and no intersecting post IDs) was also broken in that it would query the post with ID 1.

Finally, this commit significantly improves test coverage for the sticky filter argument, including direct testing of the WHERE clauses generated by WP_Query.

Props ryelle.
Fixes #39947.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r40120 r40122  
    2121
    2222        protected $forbidden_cat;
    23         protected $posts_orderby;
     23        protected $posts_clauses;
    2424
    2525        public static function wpSetUpBeforeClass( $factory ) {
     
    6969                register_post_type( 'youseeme', array( 'supports' => array(), 'show_in_rest' => true ) );
    7070                add_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 );
    71                 add_filter( 'posts_orderby', array( $this, 'save_posts_orderby' ), 10, 2 );
     71                add_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 );
    7272        }
    7373
    7474        public function wpSetUpBeforeRequest( $result, $server, $request ) {
    75                 $this->posts_orderby = array();
     75                $this->posts_clauses = array();
    7676                return $result;
    7777        }
    7878
    79         public function save_posts_orderby( $orderby, $query ) {
    80                 array_push( $this->posts_orderby, $orderby );
     79        public function save_posts_clauses( $orderby, $query ) {
     80                array_push( $this->posts_clauses, $orderby );
    8181                return $orderby;
    8282        }
    8383
     84        public function assertPostsClause( $clause, $pattern ) {
     85                global $wpdb;
     86                $expected_clause = str_replace( '{posts}', $wpdb->posts, $pattern );
     87                $this->assertCount( 1, $this->posts_clauses );
     88                $this->assertEquals( $expected_clause, $this->posts_clauses[0][ $clause ] );
     89        }
     90
    8491        public function assertPostsOrderedBy( $pattern ) {
    85                 global $wpdb;
    86                 $orderby = str_replace( '{posts}', $wpdb->posts, $pattern );
    87                 $this->assertEquals( array( $orderby ), $this->posts_orderby );
     92                $this->assertPostsClause( 'orderby', $pattern );
     93        }
     94
     95        public function assertPostsWhere( $pattern ) {
     96                $this->assertPostsClause( 'where', $pattern );
    8897        }
    8998
     
    691700        }
    692701
    693         public function test_get_items_sticky_query() {
     702        public function test_get_items_sticky() {
    694703                $id1 = self::$post_id;
    695704                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     
    712721        }
    713722
    714         public function test_get_items_sticky_with_post__in_query() {
     723        public function test_get_items_sticky_with_include() {
    715724                $id1 = self::$post_id;
    716725                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     
    726735                $this->assertCount( 0, $response->get_data() );
    727736
     737                // FIXME Since this request returns zero posts, the query is executed twice.
     738                $this->assertCount( 2, $this->posts_clauses );
     739                $this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 );
     740
     741                $this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
     742
    728743                update_option( 'sticky_posts', array( $id1, $id2 ) );
    729744
     
    739754                $post = $posts[0];
    740755                $this->assertEquals( $id1, $post['id'] );
    741         }
    742 
    743         public function test_get_items_not_sticky_query() {
     756
     757                $this->assertPostsWhere( " AND {posts}.ID IN ($id1) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
     758        }
     759
     760        public function test_get_items_sticky_no_sticky_posts() {
     761                $id1 = self::$post_id;
     762
     763                update_option( 'sticky_posts', array() );
     764
     765                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     766                $request->set_param( 'sticky', true );
     767
     768                $response = $this->server->dispatch( $request );
     769                $this->assertCount( 0, $response->get_data() );
     770
     771                // FIXME Since this request returns zero posts, the query is executed twice.
     772                $this->assertCount( 2, $this->posts_clauses );
     773                $this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 );
     774
     775                $this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
     776        }
     777
     778        public function test_get_items_sticky_with_include_no_sticky_posts() {
     779                $id1 = self::$post_id;
     780
     781                update_option( 'sticky_posts', array() );
     782
     783                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     784                $request->set_param( 'sticky', true );
     785                $request->set_param( 'include', array( $id1 ) );
     786
     787                $response = $this->server->dispatch( $request );
     788                $this->assertCount( 0, $response->get_data() );
     789
     790                // FIXME Since this request returns zero posts, the query is executed twice.
     791                $this->assertCount( 2, $this->posts_clauses );
     792                $this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 );
     793
     794                $this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
     795        }
     796
     797        public function test_get_items_not_sticky() {
    744798                $id1 = self::$post_id;
    745799                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     
    756810                $post = $posts[0];
    757811                $this->assertEquals( $id1, $post['id'] );
    758         }
    759 
    760         public function test_get_items_sticky_with_post__not_in_query() {
     812
     813                $this->assertPostsWhere( " AND {posts}.ID NOT IN ($id2) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
     814        }
     815
     816        public function test_get_items_not_sticky_with_exclude() {
    761817                $id1 = self::$post_id;
    762818                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     
    775831                $post = $posts[0];
    776832                $this->assertEquals( $id1, $post['id'] );
     833
     834                $this->assertPostsWhere( " AND {posts}.ID NOT IN ($id3,$id2) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
     835        }
     836
     837        public function test_get_items_not_sticky_with_exclude_no_sticky_posts() {
     838                $id1 = self::$post_id;
     839                $id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     840                $id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
     841
     842                update_option( 'sticky_posts', array() );
     843
     844                $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
     845                $request->set_param( 'sticky', false );
     846                $request->set_param( 'exclude', array( $id3 ) );
     847
     848                $response = $this->server->dispatch( $request );
     849                $this->assertCount( 2, $response->get_data() );
     850
     851                $posts = $response->get_data();
     852                $ids = wp_list_pluck( $posts, 'id' );
     853                sort( $ids );
     854                $this->assertEquals( array( $id1, $id2 ), $ids );
     855
     856                $this->assertPostsWhere( " AND {posts}.ID NOT IN ($id3) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
    777857        }
    778858
     
    29713051                }
    29723052                remove_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 );
    2973                 remove_filter( 'posts_orderby', array( $this, 'save_posts_orderby' ), 10, 2 );
     3053                remove_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 );
    29743054                parent::tearDown();
    29753055        }
Note: See TracChangeset for help on using the changeset viewer.