There are many ways you can order a WordPress query, and you can tie multiple orderby parameters together. But if you want to order by multiple meta_keys, you’ll need a bit extra code.
I worked on a property listings website which had featured listings and normal listings. Featured listings always appeared before normal listings. Users also had the ability to change the sort order between most recent, price low to high, and price high to low.
The code below allowed my query to sort first by featured (meta_key with a 1/0 for featured/not featured), then by price (another meta_key). You need to define the meta keys in the query, which is why I’m querying for posts where that key exists. Then on the posts_orderby filter you can update it to order by these parameters.
For more information on customizing queries, see my post on Customizing the WordPress Query.
<?php | |
/** | |
* Order results by multiple meta keys | |
* @author Bill Erickson | |
* @link http://www.billerickson.net/code/order-results-multiple-meta_keys/ | |
*/ | |
/** | |
* Listing Query | |
* | |
* @param object $query, WordPress Query | |
* @return null | |
* | |
* @author Bill Erickson | |
*/ | |
function be_listing_query( $query ) { | |
if( $query->is_main_query() && !is_admin() && ( is_post_type_archive( 'listings' ) || is_tax( array( 'listing-type', 'listing-location', 'listing-price' ) ) ) ) { | |
$sort = isset( $_GET['listing-sort'] ) ? esc_attr( $_GET['listing-sort'] ) : 'recent'; | |
// Sort by Featured, then Most Recent | |
if( 'recent' == $sort ) { | |
$query->set( 'orderby', array( 'meta_value_num' => 'DESC', 'date' => 'DESC' ) ); | |
$query->set( 'meta_key', 'be_listing_featured' ); | |
} | |
// Sort by Featured, then Price (orderby filter toggles low/high) | |
if( in_array( $sort, array( 'price_low', 'price_high' ) ) ) { | |
$query->set( 'orderby', 'meta_value_num' ); | |
$query->set( 'order', 'DESC' ); | |
$query->set( 'meta_key', 'be_listing_featured' ); | |
$query->set( 'meta_query', array( | |
'relation' => 'AND', | |
array( 'key' => 'be_listing_featured', 'compare' => 'EXISTS' ), | |
array( 'key' => 'be_listing_asking_price', 'compare' => 'EXISTS' ) | |
) | |
); | |
} | |
} | |
} | |
add_action( 'pre_get_posts', 'be_listing_query' ); | |
/** | |
* Listing Orderby | |
* | |
* @param string $orderby, SQL orderby parameter | |
* @return string $orderby | |
* | |
* @author Bill Erickson | |
*/ | |
function be_listing_orderby( $orderby ) { | |
if( is_post_type_archive( 'listings' ) || is_tax( array( 'listing-type', 'listing-location', 'listing-price' ) ) ) { | |
$sort = isset( $_GET['listing-sort'] ) ? esc_attr( $_GET['listing-sort'] ) : false; | |
if( 'price_low' == $sort ) | |
$orderby = 'mt1.meta_value+0 DESC, mt2.meta_value+0 ASC'; | |
if( 'price_high' == $sort ) | |
$orderby = 'mt1.meta_value+0 DESC, mt2.meta_value+0 DESC'; | |
} | |
return $orderby; | |
} | |
add_filter( 'posts_orderby', 'be_listing_orderby' ); |