Ordenar entradas por taxonomía y valor meta
Es posible ordenar entradas por valor meta.
Es posible ordenar entradas por más de un valor.
Y gracias al código de abajo es posible ordenar por taxonomía.
¿Pero cómo puedo modificar el código de abajo para ordenar por taxonomía Y meta_value?
Añadido a functions.php
function orderby_tax_clauses( $clauses, $wp_query ) {
global $wpdb;
$taxonomies = get_taxonomies();
foreach ($taxonomies as $taxonomy) {
if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby'] ) {
$clauses['join'] .=<<<SQL
LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID={$wpdb- >term_relationships}.object_id
LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
SQL;
$clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
$clauses['groupby'] = "object_id";
$clauses['orderby'] = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC) ";
$clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get('order') ) ) ? 'ASC' : 'DESC';
}
}
return $clauses;
}
add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );
Añadido a index.php
<?php $args = array(
'post_type' => 'custom_post_type',
'posts_per_page' => -1,
'meta_key' => '_EventStartDate',
'orderby' => 'taxonomy_cat',
'order' => asc
);
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query- >the_post(); ?>
etc. etc.
Cambiar esto no funciona
'orderby' => 'taxonomy_cat meta_value',
En tu código, existe
if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby']
que hace que tu código no funcione con múltiples campos de ordenación, porque si configuras
'orderby' => 'taxonomy_cat meta_value'
entonces $taxonomy == $wp_query->query['orderby']
nunca será verdadero.
Además, considero que recorrer todas las taxonomías solo con el objetivo de encontrar la taxonomía por la cual ordenar es de bajo rendimiento y no muy confiable.
Así que edité un poco tu código: cuando quieras ordenar por una taxonomía, tu argumento debería ser algo como:
'orderby' => 'taxonomy.taxonomy_cat'
gracias al 'taxonomy.'
es fácil reconocer la taxonomía y no hay necesidad de recorrer todas las taxonomías.
Además, WordPress solo permite pasar un argumento como 'order'
, así que cuando pasas múltiples argumentos 'orderby'
, el resultado puede no ser el esperado.
Por lo tanto, modifiqué tu código para aceptar un argumento adicional: 'ordertax'
. Este es opcional, así que si no lo pasas, se usará el argumento 'order'. También se ignora si 'orderby'
no contiene ningún argumento de taxonomía.
Si usas múltiples argumentos 'orderby'
sin pasar 'ordertax'
, todos los argumentos se ordenarán según el argumento 'order'
(o DESC por defecto), así que usando
'orderby' => 'taxonomy.taxonomy_cat meta_value',
'order' => 'ASC'
significa "ORDERBY taxonomy_cat ASC, meta_value ASC"
, mientras que usando
'orderby' => 'taxonomy.taxonomy_cat meta_value',
'ordertax' => 'DESC'
'order' => 'ASC'
significa "ORDERBY taxonomy_cat DESC, meta_value ASC"
.
Aquí está el código:
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;
}
Úsalo así:
$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 );
Ten en cuenta que usar mi código (al igual que el tuyo) con un WP_Query que contenga una consulta de taxonomía puede causar problemas... por esta razón es importante eliminar el filtro después de haberlo usado.
