Make WordPress Core

Changeset 44452


Ignore:
Timestamp:
01/08/2019 03:32:04 AM (6 years ago)
Author:
boonebgorges
Message:

Query: Standardize treatment of 'orderby' values post__in, post_parent__in, and post_name__in.

Ordering by post__in was introduced in [21776], but the code assumed that
post__in would be a comma-separated string listing post IDs. When an array
of post IDs was passed to the post__in query var, 'orderby=postin' was
not respected. This changeset changes this behavior by handling
'orderby=post
in' in the same way as most other values of 'orderby',
which ensures that arrays as well as strings can be properly parsed.

The same treatment is given to the similar post_name__in and
post_parent__in options of 'orderby', so that most query generation for
orderby clauses happens in the same place, instead of in special cases.

A slight change in the resulting SQL (related to the whitespace around
parentheses and commas) necessitates a change to an existing REST API test
that does a string comparison against the SQL query.

Props mgibbs189, kelvink.
Fixes #38034.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-query.php

    r44276 r44452  
    15471547            'comment_count',
    15481548            'rand',
     1549            'post__in',
     1550            'post_parent__in',
     1551            'post_name__in',
    15491552        );
    15501553
     
    15761579            return false;
    15771580        }
     1581
     1582        $orderby_clause = '';
    15781583
    15791584        switch ( $orderby ) {
     
    16041609                $orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
    16051610                break;
     1611            case 'post__in':
     1612                if ( ! empty( $this->query_vars['post__in'] ) ) {
     1613                    $orderby_clause = "FIELD({$wpdb->posts}.ID," . implode( ',', array_map( 'absint', $this->query_vars['post__in'] ) ) . ')';
     1614                }
     1615                break;
     1616            case 'post_parent__in':
     1617                if ( ! empty( $this->query_vars['post_parent__in'] ) ) {
     1618                    $orderby_clause = "FIELD( {$wpdb->posts}.post_parent," . implode( ', ', array_map( 'absint', $this->query_vars['post_parent__in'] ) ) . ' )';
     1619                }
     1620                break;
     1621            case 'post_name__in':
     1622                if ( ! empty( $this->query_vars['post_name__in'] ) ) {
     1623                    $post_name__in = array_map( 'sanitize_title_for_query', $this->query_vars['post_name__in'] );
     1624                    $post_name__in_string = "'" . implode( "','", $post_name__in ) . "'";
     1625                    $orderby_clause = "FIELD( {$wpdb->posts}.post_name," . $post_name__in_string . ' )';
     1626                }
     1627                break;
    16061628            default:
    16071629                if ( array_key_exists( $orderby, $meta_clauses ) ) {
     
    22402262        }
    22412263
     2264        // These values of orderby should ignore the 'order' parameter.
     2265        $force_asc = array( 'post__in', 'post_name__in', 'post_parent__in' );
     2266        if ( isset( $q['orderby'] ) && in_array( $q['orderby'], $force_asc, true ) ) {
     2267            $q['order'] = '';
     2268        }
     2269
    22422270        // Order by.
    22432271        if ( empty( $q['orderby'] ) ) {
     
    22532281        } elseif ( 'none' == $q['orderby'] ) {
    22542282            $orderby = '';
    2255         } elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
    2256             $orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
    2257         } elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
    2258             $orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
    2259         } elseif ( $q['orderby'] == 'post_name__in' && ! empty( $post_name__in ) ) {
    2260             $orderby = "FIELD( {$wpdb->posts}.post_name, $post_name__in )";
    22612283        } else {
    22622284            $orderby_array = array();
  • trunk/tests/phpunit/tests/post/query.php

    r43571 r44452  
    172172            )
    173173        );
     174        $this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
     175    }
     176
     177    /**
     178     * @ticket 38034
     179     */
     180    public function test_orderby_post__in_array() {
     181        $posts = self::factory()->post->create_many( 4 );
     182
     183        $ordered = array( $posts[2], $posts[0], $posts[3] );
     184
     185        $q = new WP_Query( array(
     186            'post_type' => 'any',
     187            'post__in' => $ordered,
     188            'orderby' => array( 'post__in' => 'ASC' ),
     189        ) );
     190        $this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
     191    }
     192
     193    /**
     194     * @ticket 38034
     195     */
     196    public function test_orderby_post__in_array_with_implied_order() {
     197        $posts = self::factory()->post->create_many( 4 );
     198
     199        $ordered = array( $posts[2], $posts[0], $posts[3] );
     200
     201        $q = new WP_Query( array(
     202            'post_type' => 'any',
     203            'post__in' => $ordered,
     204            'orderby' => 'post__in',
     205        ) );
    174206        $this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
    175207    }
  • trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r44394 r44452  
    292292        $this->assertEquals( 2, count( $data ) );
    293293        $this->assertEquals( $id1, $data[0]['id'] );
    294         $this->assertPostsOrderedBy( "FIELD( {posts}.ID, $id1,$id3 )" );
     294        $this->assertPostsOrderedBy( "FIELD({posts}.ID,$id1,$id3)" );
    295295        // Invalid include should error
    296296        $request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
Note: See TracChangeset for help on using the changeset viewer.