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. git-svn-id: https://develop.svn.wordpress.org/trunk@29027 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
c722aca8e5
commit
8ce7c39e44
@ -2199,6 +2199,97 @@ class WP_Query {
|
||||
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.
|
||||
*
|
||||
@ -2702,12 +2793,23 @@ class WP_Query {
|
||||
|
||||
$where .= $search . $whichauthor . $whichmimetype;
|
||||
|
||||
if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) )
|
||||
if ( ! isset( $q['order'] ) ) {
|
||||
$q['order'] = 'DESC';
|
||||
} else {
|
||||
$q['order'] = $this->parse_order( $q['order'] );
|
||||
}
|
||||
|
||||
// Order by
|
||||
if ( empty($q['orderby']) ) {
|
||||
$orderby = "$wpdb->posts.post_date " . $q['order'];
|
||||
// Order by.
|
||||
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'];
|
||||
}
|
||||
} elseif ( 'none' == $q['orderby'] ) {
|
||||
$orderby = '';
|
||||
} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
|
||||
@ -2715,59 +2817,41 @@ class WP_Query {
|
||||
} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
|
||||
$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
|
||||
} else {
|
||||
// Used to filter values
|
||||
$allowed_keys = array( 'name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count', 'type' );
|
||||
if ( !empty($q['meta_key']) ) {
|
||||
$allowed_keys[] = $q['meta_key'];
|
||||
$allowed_keys[] = 'meta_value';
|
||||
$allowed_keys[] = 'meta_value_num';
|
||||
}
|
||||
$q['orderby'] = urldecode($q['orderby']);
|
||||
$q['orderby'] = addslashes_gpc($q['orderby']);
|
||||
|
||||
$orderby_array = array();
|
||||
foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
|
||||
// Only allow certain values for safety
|
||||
if ( ! in_array($orderby, $allowed_keys) )
|
||||
continue;
|
||||
if ( is_array( $q['orderby'] ) ) {
|
||||
foreach ( $q['orderby'] as $_orderby => $order ) {
|
||||
$orderby = addslashes_gpc( urldecode( $_orderby ) );
|
||||
$parsed = $this->parse_orderby( $orderby );
|
||||
|
||||
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;
|
||||
if ( ! $parsed ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
|
||||
}
|
||||
$orderby = implode( ', ', $orderby_array );
|
||||
|
||||
$orderby_array[] = $orderby;
|
||||
} else {
|
||||
$q['orderby'] = urldecode( $q['orderby'] );
|
||||
$q['orderby'] = addslashes_gpc( $q['orderby'] );
|
||||
|
||||
foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
|
||||
$parsed = $this->parse_orderby( $orderby );
|
||||
// Only allow certain values for safety.
|
||||
if ( ! $parsed ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$orderby_array[] = $parsed;
|
||||
}
|
||||
$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
|
||||
|
||||
if ( empty( $orderby ) ) {
|
||||
$orderby = "$wpdb->posts.post_date ".$q['order'];
|
||||
} else {
|
||||
$orderby .= " {$q['order']}";
|
||||
}
|
||||
}
|
||||
$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
|
||||
|
||||
if ( empty( $orderby ) )
|
||||
$orderby = "$wpdb->posts.post_date ".$q['order'];
|
||||
else
|
||||
$orderby .= " {$q['order']}";
|
||||
}
|
||||
|
||||
// Order search results by relevance only when another "orderby" is not specified in the query.
|
||||
|
@ -761,4 +761,74 @@ class Tests_Post_Query extends WP_UnitTestCase {
|
||||
$q3 = new WP_Query( array( 'post_status' => array( 'any', 'auto-draft' ) ) );
|
||||
$this->assertNotContains( "post_status <> 'auto-draft'", $q3->request );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @ticket 17065
|
||||
*/
|
||||
function test_orderby_array() {
|
||||
global $wpdb;
|
||||
|
||||
$q1 = new WP_Query( array(
|
||||
'orderby' => array(
|
||||
'type' => 'DESC',
|
||||
'name' => 'ASC'
|
||||
)
|
||||
) );
|
||||
$this->assertContains(
|
||||
"ORDER BY $wpdb->posts.post_type DESC, $wpdb->posts.post_name ASC",
|
||||
$q1->request
|
||||
);
|
||||
|
||||
$q2 = new WP_Query( array( 'orderby' => array() ) );
|
||||
$this->assertNotContains( 'ORDER BY', $q2->request );
|
||||
$this->assertNotContains( 'ORDER', $q2->request );
|
||||
|
||||
$q3 = new WP_Query( array( 'post_type' => 'post' ) );
|
||||
$this->assertContains(
|
||||
"ORDER BY $wpdb->posts.post_date DESC",
|
||||
$q3->request
|
||||
);
|
||||
|
||||
$q4 = new WP_Query( array( 'post_type' => 'post' ) );
|
||||
$this->assertContains(
|
||||
"ORDER BY $wpdb->posts.post_date DESC",
|
||||
$q4->request
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @ticket 17065
|
||||
*/
|
||||
function test_order() {
|
||||
global $wpdb;
|
||||
|
||||
$q1 = new WP_Query( array(
|
||||
'orderby' => array(
|
||||
'post_type' => 'foo'
|
||||
)
|
||||
) );
|
||||
$this->assertContains(
|
||||
"ORDER BY $wpdb->posts.post_type DESC",
|
||||
$q1->request
|
||||
);
|
||||
|
||||
$q2 = new WP_Query( array(
|
||||
'orderby' => 'title',
|
||||
'order' => 'foo'
|
||||
) );
|
||||
$this->assertContains(
|
||||
"ORDER BY $wpdb->posts.post_title DESC",
|
||||
$q2->request
|
||||
);
|
||||
|
||||
$q3 = new WP_Query( array(
|
||||
'order' => 'asc'
|
||||
) );
|
||||
$this->assertContains(
|
||||
"ORDER BY $wpdb->posts.post_date ASC",
|
||||
$q3->request
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user