Allow an `array()` to be passed as the value for `orderby` to `WP_Query`. Allows for an independent `order` value for each key.
Example: `'orderby' => array( 'title' => 'DESC', 'menu_order' => 'ASC' )`. Adds docs and unit tests. Props wonderboymusic, johnbillion, DrewAPicture, dd32, andy. See #17065. Built from https://develop.svn.wordpress.org/trunk@29027 git-svn-id: http://core.svn.wordpress.org/trunk@28815 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
725c824075
commit
dc7c246da3
|
@ -2199,6 +2199,97 @@ class WP_Query {
|
||||||
return $search_orderby;
|
return $search_orderby;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the passed orderby value is allowed, convert the alias to a
|
||||||
|
* properly-prefixed orderby value.
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
* @access protected
|
||||||
|
*
|
||||||
|
* @global wpdb $wpdb WordPress database access abstraction object.
|
||||||
|
*
|
||||||
|
* @param string $orderby Alias for the field to order by.
|
||||||
|
* @return string|bool Table-prefixed value to used in the ORDER clause. False otherwise.
|
||||||
|
*/
|
||||||
|
protected function parse_orderby( $orderby ) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// Used to filter values.
|
||||||
|
$allowed_keys = array(
|
||||||
|
'post_name', 'post_author', 'post_date', 'post_title', 'post_modified',
|
||||||
|
'post_parent', 'post_type', 'name', 'author', 'date', 'title', 'modified',
|
||||||
|
'parent', 'type', 'ID', 'menu_order', 'comment_count', 'rand',
|
||||||
|
);
|
||||||
|
|
||||||
|
$meta_key = $this->get( 'meta_key' );
|
||||||
|
if ( ! empty( $meta_key ) ) {
|
||||||
|
$allowed_keys[] = $meta_key;
|
||||||
|
$allowed_keys[] = 'meta_value';
|
||||||
|
$allowed_keys[] = 'meta_value_num';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! in_array( $orderby, $allowed_keys ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( $orderby ) {
|
||||||
|
case 'post_name':
|
||||||
|
case 'post_author':
|
||||||
|
case 'post_date':
|
||||||
|
case 'post_title':
|
||||||
|
case 'post_modified':
|
||||||
|
case 'post_parent':
|
||||||
|
case 'post_type':
|
||||||
|
case 'ID':
|
||||||
|
case 'menu_order':
|
||||||
|
case 'comment_count':
|
||||||
|
$orderby = "$wpdb->posts.{$orderby}";
|
||||||
|
break;
|
||||||
|
case 'rand':
|
||||||
|
$orderby = 'RAND()';
|
||||||
|
break;
|
||||||
|
case $meta_key:
|
||||||
|
case 'meta_value':
|
||||||
|
$type = $this->get( 'meta_type' );
|
||||||
|
if ( ! empty( $type ) ) {
|
||||||
|
$meta_type = $this->meta_query->get_cast_for_type( $type );
|
||||||
|
$orderby = "CAST($wpdb->postmeta.meta_value AS {$meta_type})";
|
||||||
|
} else {
|
||||||
|
$orderby = "$wpdb->postmeta.meta_value";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'meta_value_num':
|
||||||
|
$orderby = "$wpdb->postmeta.meta_value+0";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$orderby = "$wpdb->posts.post_" . $orderby;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $orderby;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an 'order' query variable and cast it to ASC or DESC as necessary.
|
||||||
|
*
|
||||||
|
* @since 4.0.0
|
||||||
|
* @access protected
|
||||||
|
*
|
||||||
|
* @param string $order The 'order' query variable.
|
||||||
|
* @return string The sanitized 'order' query variable.
|
||||||
|
*/
|
||||||
|
protected function parse_order( $order ) {
|
||||||
|
if ( ! is_string( $order ) || empty( $order ) ) {
|
||||||
|
return 'DESC';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 'ASC' === strtoupper( $order ) ) {
|
||||||
|
return 'ASC';
|
||||||
|
} else {
|
||||||
|
return 'DESC';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the 404 property and saves whether query is feed.
|
* Sets the 404 property and saves whether query is feed.
|
||||||
*
|
*
|
||||||
|
@ -2702,12 +2793,23 @@ class WP_Query {
|
||||||
|
|
||||||
$where .= $search . $whichauthor . $whichmimetype;
|
$where .= $search . $whichauthor . $whichmimetype;
|
||||||
|
|
||||||
if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) )
|
if ( ! isset( $q['order'] ) ) {
|
||||||
$q['order'] = 'DESC';
|
$q['order'] = 'DESC';
|
||||||
|
} else {
|
||||||
|
$q['order'] = $this->parse_order( $q['order'] );
|
||||||
|
}
|
||||||
|
|
||||||
// Order by
|
// Order by.
|
||||||
if ( empty( $q['orderby'] ) ) {
|
if ( empty( $q['orderby'] ) ) {
|
||||||
|
/*
|
||||||
|
* Boolean false or empty array blanks out ORDER BY,
|
||||||
|
* while leaving the value unset or otherwise empty sets the default.
|
||||||
|
*/
|
||||||
|
if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
|
||||||
|
$orderby = '';
|
||||||
|
} else {
|
||||||
$orderby = "$wpdb->posts.post_date " . $q['order'];
|
$orderby = "$wpdb->posts.post_date " . $q['order'];
|
||||||
|
}
|
||||||
} elseif ( 'none' == $q['orderby'] ) {
|
} elseif ( 'none' == $q['orderby'] ) {
|
||||||
$orderby = '';
|
$orderby = '';
|
||||||
} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
|
} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
|
||||||
|
@ -2715,60 +2817,42 @@ class WP_Query {
|
||||||
} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
|
} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
|
||||||
$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
|
$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
|
||||||
} else {
|
} else {
|
||||||
// Used to filter values
|
$orderby_array = array();
|
||||||
$allowed_keys = array( 'name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count', 'type' );
|
if ( is_array( $q['orderby'] ) ) {
|
||||||
if ( !empty($q['meta_key']) ) {
|
foreach ( $q['orderby'] as $_orderby => $order ) {
|
||||||
$allowed_keys[] = $q['meta_key'];
|
$orderby = addslashes_gpc( urldecode( $_orderby ) );
|
||||||
$allowed_keys[] = 'meta_value';
|
$parsed = $this->parse_orderby( $orderby );
|
||||||
$allowed_keys[] = 'meta_value_num';
|
|
||||||
|
if ( ! $parsed ) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
|
||||||
|
}
|
||||||
|
$orderby = implode( ', ', $orderby_array );
|
||||||
|
|
||||||
|
} else {
|
||||||
$q['orderby'] = urldecode( $q['orderby'] );
|
$q['orderby'] = urldecode( $q['orderby'] );
|
||||||
$q['orderby'] = addslashes_gpc( $q['orderby'] );
|
$q['orderby'] = addslashes_gpc( $q['orderby'] );
|
||||||
|
|
||||||
$orderby_array = array();
|
|
||||||
foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
|
foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
|
||||||
// Only allow certain values for safety
|
$parsed = $this->parse_orderby( $orderby );
|
||||||
if ( ! in_array($orderby, $allowed_keys) )
|
// Only allow certain values for safety.
|
||||||
|
if ( ! $parsed ) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch ( $orderby ) {
|
|
||||||
case 'menu_order':
|
|
||||||
$orderby = "$wpdb->posts.menu_order";
|
|
||||||
break;
|
|
||||||
case 'ID':
|
|
||||||
$orderby = "$wpdb->posts.ID";
|
|
||||||
break;
|
|
||||||
case 'rand':
|
|
||||||
$orderby = 'RAND()';
|
|
||||||
break;
|
|
||||||
case $q['meta_key']:
|
|
||||||
case 'meta_value':
|
|
||||||
if ( isset( $q['meta_type'] ) ) {
|
|
||||||
$meta_type = $this->meta_query->get_cast_for_type( $q['meta_type'] );
|
|
||||||
$orderby = "CAST($wpdb->postmeta.meta_value AS {$meta_type})";
|
|
||||||
} else {
|
|
||||||
$orderby = "$wpdb->postmeta.meta_value";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'meta_value_num':
|
|
||||||
$orderby = "$wpdb->postmeta.meta_value+0";
|
|
||||||
break;
|
|
||||||
case 'comment_count':
|
|
||||||
$orderby = "$wpdb->posts.comment_count";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$orderby = "$wpdb->posts.post_" . $orderby;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$orderby_array[] = $orderby;
|
$orderby_array[] = $parsed;
|
||||||
}
|
}
|
||||||
$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
|
$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
|
||||||
|
|
||||||
if ( empty( $orderby ) )
|
if ( empty( $orderby ) ) {
|
||||||
$orderby = "$wpdb->posts.post_date ".$q['order'];
|
$orderby = "$wpdb->posts.post_date ".$q['order'];
|
||||||
else
|
} else {
|
||||||
$orderby .= " {$q['order']}";
|
$orderby .= " {$q['order']}";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Order search results by relevance only when another "orderby" is not specified in the query.
|
// Order search results by relevance only when another "orderby" is not specified in the query.
|
||||||
if ( ! empty( $q['s'] ) ) {
|
if ( ! empty( $q['s'] ) ) {
|
||||||
|
|
Loading…
Reference in New Issue