WordPress.org

Make WordPress Core

Changeset 40122


Ignore:
Timestamp:
02/25/2017 05:02:17 AM (2 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.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

    r40120 r40122  
    221221        if ( isset( $registered['sticky'], $request['sticky'] ) ) {
    222222            $sticky_posts = get_option( 'sticky_posts', array() );
    223             if ( $sticky_posts && $request['sticky'] ) {
     223            if ( ! is_array( $sticky_posts ) ) {
     224                $sticky_posts = array();
     225            }
     226            if ( $request['sticky'] ) {
    224227                /*
    225228                 * As post__in will be used to only get sticky posts,
     
    235238                 */
    236239                if ( ! $args['post__in'] ) {
    237                     $args['post__in'] = array( -1 );
     240                    $args['post__in'] = array( 0 );
    238241                }
    239242            } elseif ( $sticky_posts ) {
  • 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.