How do I order by multiple custom fields using wp_query?

I have a rating system where the user can enter a custom field of either “Stars” or “Hearts”, but whichever one they choose they have to enter a value of 1 thru 5. Using wp_query, I can successfully sort by one of these custom fields, but I’m not sure how to sort by both. Here is the code I’m using to sort by one of the custom fields “Stars”:

$args=array(
'posts_per_page' => $con_review_num,
'post_type' => 'con_product_reviews',
'paged' => $paged,
'orderby' => 'meta_value',
'order' => 'DESC',
'meta_key' => 'Stars'   
);

Here is what I wish this function would do (notice the last line):

$args=array(
'posts_per_page' => $con_review_num,
'post_type' => 'con_product_reviews',
'paged' => $paged,
'orderby' => 'meta_value',
'order' => 'DESC',
'meta_key' => 'Stars Hearts'    
);

Is there another way to do that?

3 Answers
3

I had the same problem and could not find a way to make this work with wp_query alone. Instead, I caught the posts_clauses filter and stuck my order_by there. This also meant doing a few joins.

Basically, you set a function to catch the posts_clauses (or one of the more restrictive query filters; but let’s just use this for now), and then within that JOIN to the post_meta table for the fields you need, then order by them.

The important thing is to set up something to then remove the query filter. You could do it at the end of the function that catches it, but I have it separate in my plugin, so I’m going to stick with that. The ‘wp’ event works fine here.

add_filter('posts_clauses', 'filterMarkets')
add_filter('wp', 'removeQueryFilter');

public static function removeQueryFilter() {
  remove_filter('posts_clauses', 'filterMarkets');
}

public static function filterMarkets($clauses, $wp_query) {
global $wpdb;

$clauses['join'] .=<<<SQL
JOIN {$wpdb->postmeta} AS title_meta ON title_meta.post_id = {$wpdb->posts}.ID AND
title_meta.meta_key = 'fest_sortby'
JOIN {$wpdb->postmeta} AS start_date_meta ON start_date_meta.post_id = {$wpdb->posts}.ID
AND start_date_meta.meta_key = 'fest_market_start_date'
SQL;

  $clauses['orderby'] .= " title_meta.meta_value ASC";
  $clauses['orderby'] .= " start_date_meta.meta_value ASC";
}
return $clauses;

}

Leave a Comment