Сортировка записей по таксономии и мета-значению в WordPress
Возможно сортировать записи по meta_value.
Возможно сортировать записи по нескольким значениям.
И благодаря коду ниже можно сортировать по таксономии.
Но как изменить код ниже, чтобы сортировать одновременно по таксономии И meta_value?
Добавлено в 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 );
Добавлено в 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(); ?>
и т.д.
Такой вариант не работает
'orderby' => 'taxonomy_cat meta_value',
В вашем коде есть
if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby']
что делает ваш код нерабочим при множественных полях сортировки, потому что если вы укажете
'orderby' => 'taxonomy_cat meta_value'
то условие $taxonomy == $wp_query->query['orderby']
никогда не будет истинным.
Кроме того, я считаю, что перебор всех таксономий только для поиска таксономии для сортировки неэффективен и не очень надежен.
Поэтому я немного изменил ваш код: когда вы хотите сортировать по таксономии, аргумент должен выглядеть примерно так:
'orderby' => 'taxonomy.taxonomy_cat'
Благодаря префиксу 'taxonomy.'
легко распознать таксономию, и нет необходимости перебирать все таксономии.
После этого WordPress позволяет передавать только один аргумент в параметре 'order'
, поэтому при передаче нескольких аргументов в 'orderby'
результат может быть неожиданным.
Поэтому я изменил ваш код, добавив дополнительный аргумент: 'ordertax'
. Конечно, он необязателен, поэтому если вы его не передадите, будет использован аргумент 'order'. Он также игнорируется, если 'orderby'
не содержит аргументов таксономии.
Если вы используете несколько аргументов 'orderby'
без передачи 'ordertax'
, все аргументы сортируются на основе параметра 'order'
(или по умолчанию 'DESC'), поэтому использование
'orderby' => 'taxonomy.taxonomy_cat meta_value',
'order' => 'ASC'
означает "ORDERBY taxonomy_cat ASC, meta_value ASC"
, а использование
'orderby' => 'taxonomy.taxonomy_cat meta_value',
'ordertax' => 'DESC'
'order' => 'ASC'
означает "ORDERBY taxonomy_cat DESC, meta_value ASC"
.
Теперь сам код:
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;
}
Используйте его так:
$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 );
Обратите внимание, что использование моего кода (как и вашего) с WP_Query, содержащим запрос таксономии, может привести к проблемам... по этой причине важно удалять фильтр после его использования.
