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 { |
1546 | 1546 | 'menu_order', |
1547 | 1547 | 'comment_count', |
1548 | 1548 | 'rand', |
| 1549 | 'post__in', |
1549 | 1550 | ); |
1550 | 1551 | |
1551 | 1552 | $primary_meta_key = ''; |
… |
… |
class WP_Query { |
1603 | 1604 | case 'meta_value_num': |
1604 | 1605 | $orderby_clause = "{$primary_meta_query['alias']}.meta_value+0"; |
1605 | 1606 | 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; |
1606 | 1612 | default: |
1607 | 1613 | if ( array_key_exists( $orderby, $meta_clauses ) ) { |
1608 | 1614 | // $orderby corresponds to a meta_query clause. |
… |
… |
class WP_Query { |
1627 | 1633 | * @since 4.0.0 |
1628 | 1634 | * |
1629 | 1635 | * @param string $order The 'order' query variable. |
| 1636 | * @param string $orderby The 'orderby' query variable. |
1630 | 1637 | * @return string The sanitized 'order' query variable. |
1631 | 1638 | */ |
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 ''; |
1635 | 1642 | } |
1636 | 1643 | |
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 ) ) { |
1638 | 1648 | return 'ASC'; |
1639 | | } else { |
| 1649 | } |
| 1650 | |
| 1651 | if ( ! is_string( $order ) || empty( $order ) ) { |
1640 | 1652 | return 'DESC'; |
1641 | 1653 | } |
| 1654 | |
| 1655 | return ( 'ASC' === strtoupper( $order ) ) ? 'ASC' : 'DESC'; |
1642 | 1656 | } |
1643 | 1657 | |
1644 | 1658 | /** |
… |
… |
class WP_Query { |
2232 | 2246 | $where .= $clauses['where']; |
2233 | 2247 | } |
2234 | 2248 | |
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 | | |
2242 | 2249 | // 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 ) ) { |
2244 | 2256 | /* |
2245 | 2257 | * Boolean false or empty array blanks out ORDER BY, |
2246 | 2258 | * while leaving the value unset or otherwise empty sets the default. |
2247 | 2259 | */ |
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"; |
2252 | 2262 | } |
2253 | | } elseif ( 'none' == $q['orderby'] ) { |
| 2263 | } |
| 2264 | elseif ( 'none' == $orderby ) { |
2254 | 2265 | $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 ) ) { |
2258 | 2268 | $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 ) ) { |
2260 | 2271 | $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; |
2262 | 2284 | $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 | } |
2286 | 2286 | |
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 ); |
2290 | 2291 | |
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 ); |
2295 | 2295 | } |
2296 | 2296 | } |
| 2297 | |
| 2298 | $orderby = implode( ', ', $orderby_array ); |
| 2299 | } |
| 2300 | elseif ( ! empty( $orderby ) && ! empty( $order ) ) { |
| 2301 | $orderby .= " $order"; |
2297 | 2302 | } |
2298 | 2303 | |
2299 | 2304 | // Order search results by relevance only when another "orderby" is not specified in the query. |
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 { |
174 | 174 | $this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) ); |
175 | 175 | } |
176 | 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 | ) ); |
| 206 | $this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) ); |
| 207 | } |
| 208 | |
177 | 209 | function test_post__in_attachment_ordering() { |
178 | 210 | $post_id = self::factory()->post->create(); |
179 | 211 | $att_ids = array(); |