Order WP_Query by taxonomy
/* --------------------------------- */
/* Order WP_Query By Taxonomy
/* --------------------------------- */
/*
*** Note: THIS MAY BREAK if used with a WP_Query containing a taxonomy query ***
Usage:
$args = array(
'post_type' => 'custom_post_type',
'posts_per_page' => -1,
'meta_key' => '_EventStartDate',
'orderby' => 'taxonomy.taxonomy_cat meta_value',
'ordertax' => 'ASC',
'order' => 'DESC'
);
add_filter( 'posts_clauses', 'orderby_tax_clauses', 10, 2 );
$the_query = new WP_Query( $args );
remove_filter( 'posts_clauses', 'orderby_tax_clauses', 10, 2 );
*/
function orderby_tax_clauses( $clauses, $wp_query ) {
$orderby_arg = $wp_query->get('orderby');
if ( ! empty( $orderby_arg ) && substr_count( $orderby_arg, 'taxonomy.' ) ) {
global $wpdb;
$bytax = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC)";
$array = explode( ' ', $orderby_arg );
if ( ! isset( $array[1] ) ) {
$array = array( $bytax, "{$wpdb->posts}.post_date" );
$taxonomy = str_replace( 'taxonomy.', '', $orderby_arg );
} else {
foreach ( $array as $i => $t ) {
if ( substr_count( $t, 'taxonomy.' ) ) {
$taxonomy = str_replace( 'taxonomy.', '', $t );
$array[$i] = $bytax;
} elseif ( $t === 'meta_value' || $t === 'meta_value_num' ) {
$cast = ( $t === 'meta_value_num' ) ? 'SIGNED' : 'CHAR';
$array[$i] = "CAST( {$wpdb->postmeta}.meta_value AS {$cast} )";
} else {
$array[$i] = "{$wpdb->posts}.{$t}";
}
}
}
$order = strtoupper( $wp_query->get('order') ) === 'ASC' ? ' ASC' : ' DESC';
$ot = strtoupper( $wp_query->get('ordertax') );
$ordertax = $ot === 'DESC' || $ot === 'ASC' ? " $ot" : " $order";
$clauses['orderby'] = implode(', ',
array_map( function($a) use ( $ordertax, $order ) {
return ( strpos($a, 'GROUP_CONCAT') === 0 ) ? $a . $ordertax : $a . $order;
}, $array )
);
$clauses['join'] .= " LEFT OUTER JOIN {$wpdb->term_relationships} ";
$clauses['join'] .= "ON {$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id";
$clauses['join'] .= " LEFT OUTER JOIN {$wpdb->term_taxonomy} ";
$clauses['join'] .= "USING (term_taxonomy_id)";
$clauses['join'] .= " LEFT OUTER JOIN {$wpdb->terms} USING (term_id)";
$clauses['groupby'] = "object_id";
$clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
}
return $clauses;
}
/*
Additional Note:
'orderby' => 'taxonomy.taxonomy_cat meta_value',
'ordertax' => 'DESC'
'order' => 'ASC'
means "ORDERBY taxonomy_cat DESC, meta_value ASC"
'orderby' => 'taxonomy.taxonomy_cat meta_value',
'order' => 'ASC'
means "ORDERBY taxonomy_cat ASC, meta_value ASC"
/* Source: http://wordpress.stackexchange.com/questions/137208/order-posts-by-taxonomy-and-meta-value */