Сортировка терминов по term_order
Контекст
- Тип записи: Resources
- Таксономия: Media Type, Термин: Audio
- Таксономия: Series
Следующий код отображает уникальный список пользовательской таксономии "Series"
Я хочу отсортировать список по term_order, но это не работает. Есть предложения?
Сайт. В настоящее время сортировка идет по ID
<?php
// Массив для данных записей
$post_data = array();
$my_query = new WP_Query( array(
'post_type' => 'resource',
'posts_per_page' => -1,
'media_type' => 'audio'
)
);
if ( $my_query->have_posts() ) {
while ( $my_query->have_posts() ) {
$my_query->the_post();
$post_data[] = get_the_ID();
}
}
// Начать с любого ID, который вы хотите получить из Media Type
$audio = 16;
// Получить все ID записей для этого термина
$post_ids = get_objects_in_term( $audio, 'media_type', array('post_status' => 'publish') );
// Затем получить термины series для этих ID записей
$terms = wp_get_object_terms( $post_data, 'series', array('fields' => 'ids', 'orderby' => 'menu_order' ) );
$result = array_values( array_unique($terms) );
?>
<?php
$a = $result;
foreach ($a as $v) {
$term = get_term( $v, 'series' );
$name = $term->name;
$slug = $term->slug;
echo '<div class="resource-item"><a href="'.get_term_link($slug, 'series').'" title="'.$name.'"><div class="play"></div><li>'.$name.'</li></a></div>';
}
?>

Так как это один из топовых результатов в Google, и ни один из вышеперечисленных вариантов мне не подошел, этот способ действительно возвращает термины в порядке, соответствующем их отображению в админке...
get_terms([
'taxonomy' => 'whatever_you_want',
'meta_key' => 'order',
'orderby' => 'meta_value_num'
]);
Если кому-то пригодится: WordPress сохраняет значение в таблице termmeta с ключом order, которое соответствует позиции отображения в меню админки. Очевидно, его нужно адаптировать, если вы хотите одновременно делать запросы по другим метаполям.

Вместо menu_order
попробуйте использовать term_order
.
Согласно документации в Codex, функция wp_get_object_terms
поддерживает следующие параметры:
- name (название)
- count (количество)
- slug (ярлык)
- term_group (группа терминов)
- term_order (порядок терминов)
- term_id (ID термина)

@izharbuen Пожалуйста, отметьте этот ответ как верный, нажав на галочку рядом с ним. Спасибо :-)

@PieterGoosen izharbuen сказал, что это не работает, поэтому будет неправильно отмечать это как правильный ответ. Я могу подтвердить, что установка orderby
в term_order
не работает. Ломаю голову, пытаясь понять, почему.

Проблема в том, что wp_term_query
не принимает term_order
в качестве одного из параметров orderby
, и это сделано преднамеренно. Это просто не будет работать по задумке. Почему? WP иногда делает вещи плохо, из-за чего мне хочется разрабатывать для другой платформы.

term_order
не предназначен для упорядочивания терминов внутри таксономии. Он используется для упорядочивания терминов внутри объекта (записи).
https://developer.wordpress.org/reference/classes/wp_term_query/__construct/ гласит:
Если $object_ids не пуст, 'term_order' обрабатывается так же, как 'term_id'.
Для тех, кто пытается упорядочить термины для объекта по term_id
, необходимо передать object_ids в запрос.
Для всех остальных, кто задаётся этим вопросом и хочет упорядочить список терминов, не используйте term_id
. Вместо этого добавьте мета-значение термина и сортируйте по нему.
get_terms([
'taxonomy' => 'my_taxonomy',
'meta_key' => 'order',
'orderby' => 'meta_value_num'
]);

wp_term_query
не принимает term_order
в качестве одного из параметров сортировки. Поэтому вам нужно принудительно добавить эту опцию в переменную запроса терминов, добавив следующий код в файл functions.php.
function wpcf_filter_terms_order( $orderby, $query_vars, $taxonomies ) {
return $query_vars['orderby'] == 'term_order' ? 'term_order' : $orderby;
}
add_filter( 'get_terms_orderby', 'wpcf_filter_terms_order', 10, 3 );
После добавления этого кода, если вы выполните что-то вроде следующего, вы получите термины, отсортированные по term_order.
$terms = get_terms('category', array(
'orderby' => 'term_order',
'order' => 'ASC'
));
Второй подход: если вы хотите получать термины, отсортированные по term_order глобально и во всех частях WordPress, просто добавьте следующий код в functions.php.
function uc_get_terms_orderby($orderby, $args){
return 't.term_order';
}
add_filter('get_terms_orderby', 'uc_get_terms_orderby', 10, 2);

Много лет спустя,
Вы можете добавить этот код в свой functions.php:
function wpcf_filter_terms_order( $orderby, $query_vars, $taxonomies ) {
return $query_vars['orderby'] == 'term_order' ? 'term_order' : $orderby;
}
add_filter( 'get_terms_orderby', 'wpcf_filter_terms_order', 10, 3 );
Этот код заставляет WordPress использовать аргумент orderby => term_order в запросе терминов.

Это идея
Но я реализовал её с мыслью о сортировке списка на фронтенде
Необходимо изменить таблицу "{prefix}term_taxonomy", создав поле "term_order". Смотрите функцию O_term_update_db():
В вашем function.php
<?php
function O_term_update_db(){
global $wpdb;
global $term_db_version;
$term_db_version = "1";
$charset_collate = $wpdb->get_charset_collate();
if(get_site_option( 'O_term_db_version' ) < $term_db_version):
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
$wpdb->query( "ALTER TABLE $wpdb->prefix .'term_taxonomy' ADD `term_order` INT (11) NOT NULL DEFAULT 0;" );
update_site_option( 'O_term_db_version', $term_db_version);
endif;
}
add_action('init','O_term_update_db');
?>
Эта функция обращается к базе данных:
В вашем functions.php
<?php
function O_taxonomy_filter_by_order($taxonomy){
global $wpdb;
$terms = $wpdb->get_results("
SELECT t.*, tt.*
FROM ".$wpdb->prefix."term_taxonomy AS tt
JOIN ".$wpdb->prefix."terms AS t
ON t.term_id = tt.term_id
WHERE tt.taxonomy = '".$taxonomy."'
ORDER BY tt.term_order ASC
",ARRAY_A);
return $terms;
}
?>
Эта функция используется для обновления таблицы через Ajax:
В вашем function.php
<?php
if(!function_exists('O_updating_data_term_reorder')){
function O_updating_data_term_reorder() {
check_ajax_referer('o-nonce', 'security');
global $wpdb;
$terms_ID = $_POST['each_term'];
$new_order = 0;
foreach($terms_ID as $key => $ID):
$term_ID = $ID['term'];
$new_order++;
$result = $wpdb->update($wpdb->prefix.'term_taxonomy', array('term_order' => $new_order), array('term_id' => $term_ID));
if(is_wp_error($result)) {
echo json_encode(array('save'=>false, 'message'=> 'ОШИБКА: '.$result->get_error_message()));
exit();
}
endforeach;
echo json_encode(array('save'=>true, 'count'=>$new_order));
die();
}
add_action( 'wp_ajax_o_update_term_reorder', 'O_updating_data_term_reorder' );
}
?>
draggable-ajax.js:
(function($) {
"use strict";
//jQuery Sortable необходим http://api.jqueryui.com/sortable/
//Вызовите "wp_enqueue_script('jquery-ui-sortable');" в вашем wp_enqueue_scripts
$('.js-draggable-items > .draggable-column').sortable({
connectWith: '.draggable-column',
items: '.draggable-item',
dropOnEmpty: true,
opacity: .75,
handle: '.draggable-handler',
placeholder: 'draggable-placeholder',
tolerance: 'pointer',
start: function(e, ui){
ui.placeholder.css({
'height': ui.item.outerHeight(),
'margin-bottom': ui.item.css('margin-bottom')
});
}
});
$(document).on( "click","#btn-reorder-terms", function() {
var each_term_list = [];
$('.draggable-item').each(function(){
each_term_list.push({
term: $(this).attr('data-draggable-id'),
});
});
var data = {
'action' : 'o_update_term_reorder',
'each_term' : each_term_list,
'security' : actions_vars.nonce
};
$.ajax({
type: 'POST',
dataType: 'json',
cache: false,
url: actions_vars.ajaxurl,
data: data,
success: function(data) {
if(data.save === true){
//сообщение об успехе
alert('Готово');
}else{
//сообщение об ошибке
alert('Что-то пошло не так');
}
},
error: function(errorThrown) {
console.log(data);
}
});
});
})(jQuery);
На фронтенде попробуйте так:
<?php
$terms = O_taxonomy_filter_by_order('ваша_таксономия');
?>
<button type="button" class="btn btn-primary" id="btn-reorder-terms">Сохранить</button>
<div class="col-md-12 js-draggable-items">
<div class="row draggable-column">
<?php
foreach($terms as $key => $term):
$ID = $term['term_id'];
$name = $term['name'];
$order = $term['term_order'];
$description = $term['description'];
$link = get_category_link($ID);
?>
<div class="draggable-item" data-draggable-id="<?php echo $ID;?>" data-term-order="<?php echo $order;?>">
<div class="col-md-2 draggable-handler"><i class="si si-cursor-move"></i></div>
<div class="col-md-10"><?php echo $name;?></div>
</div>
<?php
endforeach;
?>
<div>
<div>
