Ordenar términos por term_order
Contexto
- Tipo de Entrada: Resources
- Taxonomía: Media Type, Término: Audio
- Taxonomía: Series
El siguiente código muestra una lista única de la taxonomía personalizada "Series"
Quiero ordenar la lista por term_order, pero no está funcionando. ¿Alguna sugerencia?
El sitio. Actualmente está ordenado por ID
<?php
// Arreglo para almacenar datos de posts
$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();
}
}
// Comenzar con cualquier ID que quieras tener de Media Type
$audio = 16;
// Obtener todos los post_ids para ese término
$post_ids = get_objects_in_term( $audio, 'media_type', array('post_status' => 'publish') );
// Luego obtener los términos de series para esos post ids
$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>';
}
?>

Dado que este es uno de los resultados principales en Google y ninguna de las soluciones anteriores funcionó para mí, esta sí pareció devolver los términos en un orden que coincide con su visualización en el administrador...
get_terms([
'taxonomy' => 'lo_que_quieras',
'meta_key' => 'order',
'orderby' => 'meta_value_num'
]);
Por si le sirve a alguien, WordPress almacena un valor en la tabla termmeta bajo la clave 'order' que representa su posición de visualización en los menús del administrador. Obviamente, habría que adaptarlo si se desea consultar otros metadatos al mismo tiempo.

En lugar de menu_order
prueba con term_order
.
Según la documentación en el Codex, wp_get_object_terms
soporta:
- name
- count
- slug
- term_group
- term_order y
- term_id

@izharbuen Por favor, acepta esta respuesta haciendo clic en la marca de verificación al lado. Gracias :-)

@PieterGoosen izharbuen dijo que no funciona, así que sería incorrecto marcar esto como la respuesta correcta. Puedo confirmar que configurar orderby
como term_order
no funciona. Me estoy rompiendo la cabeza para entender por qué.

term_order
no es un orden para términos dentro de una taxonomía. Es un orden para términos dentro de un objeto (post).
https://developer.wordpress.org/reference/classes/wp_term_query/__construct/ dice:
A menos que $object_ids no esté vacío, 'term_order' se trata igual que 'term_id'.
Para las personas que intentan ordenar términos para un objeto por term_id
, necesitan proporcionar object_ids a la consulta.
Para todos los demás que hacen esta pregunta, que buscan ordenar una lista de términos, no usen term_id
. En su lugar, añadan un valor de meta término y ordenen por ese.
get_terms([
'taxonomy' => 'my_taxonomy',
'meta_key' => 'order',
'orderby' => 'meta_value_num'
]);

wp_term_query
no acepta term_order
como uno de los parámetros para ordenar. Por lo tanto, debes agregar manualmente esa opción a la variable de consulta de términos añadiendo los siguientes fragmentos a tu 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 );
Después de agregar los fragmentos anteriores, si ejecutas algo como lo siguiente, obtendrás los términos ordenados por term_order.
$terms = get_terms('category', array(
'orderby' => 'term_order',
'order' => 'ASC'
));
Segundo enfoque, si deseas obtener los términos por term_order de manera global en todo WordPress, simplemente añade los siguientes fragmentos a functions.php.
function uc_get_terms_orderby($orderby, $args){
return 't.term_order';
}
add_filter('get_terms_orderby', 'uc_get_terms_orderby', 10, 2);

Muchos años después,
Puedes agregar este código en tu 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 );
Este código fuerza a WordPress a usar el argumento orderby => term_order en tu consulta de términos.

Esta es una idea
Pero lo hice pensando en ordenar un listado en el front end
Necesitas modificar la tabla "{prefix}term_taxonomy", creando el campo "term_order". Mira la función O_term_update_db():
En tu functions.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');
?>
Esta función consulta la base de datos:
En tu 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;
}
?>
Esta función se usa para actualizar la tabla vía Ajax:
En tu functions.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'=> 'ERROR: '.$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";
//Se requiere jQuery Sortable http://api.jqueryui.com/sortable/
//Llama "wp_enqueue_script('jquery-ui-sortable');" en tu 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){
//mensaje de éxito aquí
alert('Listo');
}else{
//mensaje de error aquí
alert('Algo salió mal');
}
},
error: function(errorThrown) {
console.log(data);
}
});
});
})(jQuery);
En tu listado del front end prueba esto:
<?php
$terms = O_taxonomy_filter_by_order('tu_taxonomia');
?>
<button type="button" class="btn btn-primary" id="btn-reorder-terms">Guardar</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>
