Make WordPress Core

Ticket #38034: 38034.3.diff

File 38034.3.diff, 6.7 KB (added by mgibbs189, 6 years ago)
  • src/wp-includes/class-wp-query.php

    diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php
    index e569e02ef1..f588011ae5 100644
    a b class WP_Query { 
    15461546                        'menu_order',
    15471547                        'comment_count',
    15481548                        'rand',
     1549                        'post__in',
    15491550                );
    15501551
    15511552                $primary_meta_key   = '';
    class WP_Query { 
    16031604                        case 'meta_value_num':
    16041605                                $orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
    16051606                                break;
     1607                        case 'post__in':
     1608                                if ( ! empty( $this->query_vars['post__in'] ) ) {
     1609                                        $orderby_clause = "FIELD({$wpdb->posts}.ID," . implode( ',', array_map( 'absint', $this->query_vars['post__in'] ) ) . ')';
     1610                                }
     1611                                break;
    16061612                        default:
    16071613                                if ( array_key_exists( $orderby, $meta_clauses ) ) {
    16081614                                        // $orderby corresponds to a meta_query clause.
    class WP_Query { 
    16271633         * @since 4.0.0
    16281634         *
    16291635         * @param string $order The 'order' query variable.
     1636         * @param string $orderby The 'orderby' query variable.
    16301637         * @return string The sanitized 'order' query variable.
    16311638         */
    1632         protected function parse_order( $order ) {
    1633                 if ( ! is_string( $order ) || empty( $order ) ) {
    1634                         return 'DESC';
     1639        protected function parse_order( $order, $orderby = '' ) {
     1640                if ( 'rand' === $orderby || 'none' === $orderby ) {
     1641                        return '';
    16351642                }
    16361643
    1637                 if ( 'ASC' === strtoupper( $order ) ) {
     1644                // These sorts should default to "ASC".
     1645                $default_asc = array( 'post__in', 'post_name__in', 'post_parent__in' );
     1646
     1647                if ( empty( $order ) && in_array( $orderby, $default_asc ) ) {
    16381648                        return 'ASC';
    1639                 } else {
     1649                }
     1650
     1651                if ( ! is_string( $order ) || empty( $order ) ) {
    16401652                        return 'DESC';
    16411653                }
     1654
     1655                return ( 'ASC' === strtoupper( $order ) ) ? 'ASC' : 'DESC';
    16421656        }
    16431657
    16441658        /**
    class WP_Query { 
    22322246                        $where  .= $clauses['where'];
    22332247                }
    22342248
    2235                 $rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
    2236                 if ( ! isset( $q['order'] ) ) {
    2237                         $q['order'] = $rand ? '' : 'DESC';
    2238                 } else {
    2239                         $q['order'] = $rand ? '' : $this->parse_order( $q['order'] );
    2240                 }
    2241 
    22422249                // Order by.
    2243                 if ( empty( $q['orderby'] ) ) {
     2250                $orderby_array = array();
     2251                $orderby = isset( $q['orderby'] ) ? $q['orderby'] : '';
     2252                $order = isset( $q['order'] ) ? $q['order'] : '';
     2253                $order = $this->parse_order( $order, $orderby );
     2254
     2255                if ( empty( $orderby ) ) {
    22442256                        /*
    22452257                         * Boolean false or empty array blanks out ORDER BY,
    22462258                         * while leaving the value unset or otherwise empty sets the default.
    22472259                         */
    2248                         if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
    2249                                 $orderby = '';
    2250                         } else {
    2251                                 $orderby = "{$wpdb->posts}.post_date " . $q['order'];
     2260                        if ( ! is_array( $orderby ) && false !== $orderby ) {
     2261                                $orderby  = "{$wpdb->posts}.post_date";
    22522262                        }
    2253                 } elseif ( 'none' == $q['orderby'] ) {
     2263                }
     2264                elseif ( 'none' == $orderby ) {
    22542265                        $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 ) ) {
     2266                }
     2267                elseif ( 'post_parent__in' == $orderby && ! empty( $post_parent__in ) ) {
    22582268                        $orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
    2259                 } elseif ( $q['orderby'] == 'post_name__in' && ! empty( $post_name__in ) ) {
     2269                }
     2270                elseif ( 'post_name__in' == $orderby && ! empty( $post_name__in ) ) {
    22602271                        $orderby = "FIELD( {$wpdb->posts}.post_name, $post_name__in )";
    2261                 } else {
     2272                }
     2273                /**
     2274                 * Convert 'orderby' string to an array, which supports all of the following:
     2275                 * 'orderby' => 'title'
     2276                 * 'orderby' => 'title menu_order'
     2277                 * 'orderby' => array( 'title' => ASC', 'menu_order' => 'DESC' )
     2278                 */
     2279                elseif ( is_string( $orderby ) ) {
     2280                        foreach ( explode( ' ', trim( $orderby ) ) as $key ) {
     2281                                $orderby_array[ $key ] = $order;
     2282                        }
     2283                        $orderby = $orderby_array;
    22622284                        $orderby_array = array();
    2263                         if ( is_array( $q['orderby'] ) ) {
    2264                                 foreach ( $q['orderby'] as $_orderby => $order ) {
    2265                                         $orderby = addslashes_gpc( urldecode( $_orderby ) );
    2266                                         $parsed  = $this->parse_orderby( $orderby );
    2267 
    2268                                         if ( ! $parsed ) {
    2269                                                 continue;
    2270                                         }
    2271 
    2272                                         $orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
    2273                                 }
    2274                                 $orderby = implode( ', ', $orderby_array );
    2275 
    2276                         } else {
    2277                                 $q['orderby'] = urldecode( $q['orderby'] );
    2278                                 $q['orderby'] = addslashes_gpc( $q['orderby'] );
    2279 
    2280                                 foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
    2281                                         $parsed = $this->parse_orderby( $orderby );
    2282                                         // Only allow certain values for safety.
    2283                                         if ( ! $parsed ) {
    2284                                                 continue;
    2285                                         }
     2285                }
    22862286
    2287                                         $orderby_array[] = $parsed;
    2288                                 }
    2289                                 $orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
     2287                if ( is_array( $orderby ) ) {
     2288                        foreach ( $orderby as $_orderby => $order ) {
     2289                                $orderby_clean = addslashes_gpc( urldecode( $_orderby ) );
     2290                                $parsed = $this->parse_orderby( $orderby_clean );
    22902291
    2291                                 if ( empty( $orderby ) ) {
    2292                                         $orderby = "{$wpdb->posts}.post_date " . $q['order'];
    2293                                 } elseif ( ! empty( $q['order'] ) ) {
    2294                                         $orderby .= " {$q['order']}";
     2292                                // Only allow certain values for safety.
     2293                                if ( $parsed ) {
     2294                                        $orderby_array[] = $parsed . ' ' . $this->parse_order( $order, $orderby_clean );
    22952295                                }
    22962296                        }
     2297
     2298                        $orderby = implode( ', ', $orderby_array );
     2299                }
     2300                elseif ( ! empty( $orderby ) && ! empty( $order ) ) {
     2301                        $orderby .= " $order";
    22972302                }
    22982303
    22992304                // Order search results by relevance only when another "orderby" is not specified in the query.
  • tests/phpunit/tests/post/query.php

    diff --git a/tests/phpunit/tests/post/query.php b/tests/phpunit/tests/post/query.php
    index 3e95e73605..1112c87e04 100644
    a b class Tests_Post_Query extends WP_UnitTestCase { 
    174174                $this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
    175175        }
    176176
     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                ) );
     206                $this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
     207        }
     208
    177209        function test_post__in_attachment_ordering() {
    178210                $post_id    = self::factory()->post->create();
    179211                $att_ids    = array();