¿Es posible ordenar por taxonomía usando wp_query?
Mi pregunta es sencilla, estoy usando WP_Query
para recuperar algunos posts de tipo personalizado filtrando por una taxonomía usando tax_query
.
Ahora mi problema es que me gustaría ordenar los resultados por la taxonomía
, pero según la documentación y buscando en la web no encuentro una solución.
El parámetro orderby
en WP_Query
te permite ordenar por muchos campos, incluso campos meta personalizados, pero parece que no soporta taxonomías.
¿Alguna indicación en la dirección correcta?
Gracias a todos.

La respuesta aceptada para esta pregunta es inaceptable. No es lógico asumir que ordenar por taxonomía "no tiene sentido". La respuesta que dio no tiene sentido.
Considera tener un tipo de publicación "menú". Luego tienes una taxonomía personalizada "FoodCategories" (Categorías de Comida). La taxonomía FoodCategories tiene los términos "Breakfast" (Desayuno), "Lunch" (Almuerzo) y "Dinner" (Cena). Si realizas una consulta utilizando el parámetro tax_query, obtendrás un conjunto de resultados con todos los términos, pero ordenados por fecha de publicación.
Para obtener el orden correcto de estas publicaciones en relación a sus términos, y luego mostrarlas en el front-end agrupadas apropiadamente por sus categorías, tienes que recorrer el conjunto de resultados, consultar cada publicación individual para encontrar sus términos, compararlos con el término actual, filtrarlos en un array y continuar este proceso. Luego tienes que volver a recorrer el nuevo array para mostrarlo. Esto no es productivo.
Sería bueno si WordPress tuviera una opción "tax__in" para orderby como tiene "post__in", pero como no la tiene, tienes que hacer el ridículo proceso mencionado anteriormente; personalizar la consulta manualmente usando los filtros 'posts_orderby' y 'posts_join' para ajustar el método de ordenación y añadir el término al conjunto de resultados, respectivamente; o hacer una nueva consulta para cada término que estés filtrando dentro de las secciones HTML correspondientes a esos términos.
Lo más eficiente sería modificar la cadena de consulta usando filtros. Lo más fácil sería hacer tres consultas separadas. La API de WordPress debería manejar el ordenamiento por taxonomía, o cualquier parámetro de consulta restrictivo. Si estás restringiendo una consulta basada en ciertas condiciones, hay una alta probabilidad de que muchos necesiten ordenar por esas mismas condiciones.

Lo siento, pero estás equivocado. Ordenar por taxonomía no tiene sentido en tu caso tampoco. ¿Qué quieres mostrar? ¿Todos los Desayunos primero, seguidos de todas las Cenas, luego todos los Almuerzos? Deberías seleccionar lo que quieres y el orden en que lo quieres, pero la taxonomía es solo una etiqueta de agrupación. No son "datos" significativos por los que deberías ordenar. Si lo son, entonces no debería ser un término en una taxonomía, deberías convertirlo en un post-meta.

Vamos, claro que habrá casos en los que querrás ordenar posts por términos de taxonomía. Otro ejemplo es un tipo de post Película con una taxonomía de Clasificación. En una lista de películas, es fácil imaginar que la gente quiera ordenar una lista de películas por clasificación para que todas las películas con clasificación G, luego PG, etc. aparezcan al principio. (En este y el ejemplo de comidas podrían ordenarse por term_id en lugar de name.) Hay una gran área gris de casos donde probablemente sea mejor usar una taxonomía y no meta, pero también sería útil que esa taxonomía se pueda ordenar.

Las clasificaciones PG, G y similares son una buena elección de taxonomía, excepto que son datos sobre películas específicas. Por lo tanto, son meta. Son datos, no categorías. El simple hecho de tener un número limitado de opciones no convierte algo en taxonomía. Si necesita ordenarse, entonces conviértelo en meta o fuerza el orden mediante código específico de taxonomía. Por cierto, NC17 va después de PG. Así que necesitarás código para hacer ese ordenamiento de todas formas.

Sé que llego tarde a la fiesta con este comentario, pero acabo de toparme con esto. Ordenar por taxonomía puede tener sentido en algunas situaciones. Tenemos listados de trabajos en un proyecto como un tipo de publicación y luego Estado y Ciudad donde está el trabajo como taxonomías. Queremos que sean fácilmente agrupables (mostrar todos los trabajos en un estado o mostrar todos los trabajos en una ciudad), así que la taxonomía fue la mejor solución. Al mismo tiempo, hay una búsqueda general de trabajos donde queremos ordenarlos primero por título, luego por estado y luego por ciudad.

Otro caso de uso: Un cliente tiene varios artículos, cada uno con una categoría. El cliente quiere que haya una página que liste todos los artículos, que se puedan ordenar alfabéticamente, por fecha o por categoría. Las categorías también se pueden filtrar, pero listar todos los artículos por categoría en orden alfabético no es un caso de uso tan descabellado y lo ves aparecer bastante a menudo.

Otro caso de uso aquí: tenemos varios 'clientes' en un tipo de publicación personalizado, y hay una taxonomía de región que nos permite indicar dónde cada cliente realiza su negocio. Nos han pedido que agreguemos funcionalidad para que cuando un visitante vea la lista de clientes, los vea ordenados por región, con los clientes cercanos a ellos primero.

Otto tiene razón en que si estás intentando hacer esto, debes revisar tu estructura de datos; nueve de cada diez veces está mal. SIN EMBARGO, insistir dogmáticamente en que "todos los demás están equivocados" simplemente no es inteligente. Este es mi caso de uso: Los apellidos deben ordenarse por la primera letra en mayúscula; de Courcy va bajo C y De Haan bajo D. Es fácil crear una taxonomía personalizada con regex que ordene estos correctamente; sin embargo, ahora mostrar todas mis personas con una consulta simple (a través de 'meta_key' => 'alphabet') no es posible. Tengo que duplicar mi código y definir mi propio filtro 'orderby' => 'quasi_alphabetic_by_title'.

Sí, pero es bastante complejo...
Añade esto al functions.php de tu tema:
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 );
Esto es una combinación de código encontrado y cosas que hice yo mismo. Explicarlo es bastante difícil, pero en resumen, con esto funcionando, puedes poner ?orderby=(taxonomia)&order=ASC (o DESC) y ¡funcionará perfectamente!

Gracias Drew, voy a intentar ejecutar ese SQL, necesito editarlo un poco, pero podría funcionar. Mi único problema ahora es que podría estar yendo en la dirección equivocada como señaló Otto. Gracias Drew. EDIT- No necesito editar, ya puedo ver dónde necesita ajustes :) Gracias

Si lo copiaste en los últimos dos minutos, no funcionará, vuelve a copiarlo ahora, lo arreglé. Estaba configurado para dos taxonomías específicas, mejoré el código para que funcione con todas las taxonomías registradas.

Gracias de nuevo. Por si acaso probé tu solución y funciona más o menos. También, si alguien más quiere usarlo, necesitas cambiar add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );
por add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );
Gracias :)

Sí, esto ya está corregido en el bloque de código, lo tomé de un proyecto en el que estoy trabajando y olvidé cambiar el nombre de la función aunque lo cambié en el hook.

¿Sabes si es posible ordenar las taxonomías por ID en lugar de por nombre? Estoy intentando obtener el mismo resultado ordenando los grupos de taxonomías por ID

No, no es posible ordenar por taxonomía, porque desde cierto punto de vista, eso en realidad no tiene mucho sentido.
Las taxonomías son formas de agrupar cosas. Así que el propósito de tener una taxonomía en las publicaciones sería realmente tener términos en esa taxonomía que sean compartidos entre las publicaciones. Si una taxonomía tuviera términos que solo se usaran en una publicación cada uno, entonces eso haría que la taxonomía careciera de sentido. Y si los términos se compartieran como deberían ser, entonces ordenar por ellos no produciría nada particularmente útil.
Lo que deberías usar en tal situación son los metadatos de la publicación. Puedes ordenar por metadatos de publicación, y son únicos para cada publicación.
Edición: Dicho esto, puedes ordenar por taxonomía haciendo una consulta SQL personalizada usando un filtro, simplemente no puedes hacerlo desde un WP_Query sin modificar: http://scribu.net/wordpress/sortable-taxonomy-columns.html
Sin embargo, si tienes que recurrir a hacer este tipo de cosas, entonces tu estructura de diseño de datos está mal desde el principio. Los "términos" en la taxonomía no son "datos" reales. Los términos en sí mismos no tienen un significado inherente, solo son etiquetas para la agrupación particular que describen. Si los estás tratando como datos significativos, entonces tienes un error de diseño subyacente.
Las taxonomías agrupan cosas asignándoles términos. Esa agrupación es el propósito principal de las taxonomías, los términos son solo caras bonitas en la agrupación. Si tienes metadatos significativos para asignar a una publicación, entonces deberías usar los metadatos de la publicación para ello. Y eso sí puedes ordenar, porque los metadatos de publicación usan tanto claves como valores para almacenar información. Con una taxonomía, en realidad solo estás almacenando claves, siendo sus valores las publicaciones agrupadas por ese término.
Las cosas son más fáciles a largo plazo si usas el enfoque correcto. Aunque no estoy diciendo que no puedas hacer algo extraño con la taxonomía, solo te estás complicando las cosas a largo plazo usándola incorrectamente.

Hola Otto, gracias por la respuesta. Entiendo tu punto y tal vez esté tomando el camino equivocado con esto. En mi ejemplo de un sitio de series de TV, tengo una taxonomía para serie 1, serie 2, serie 3, etc. Así puedo agrupar todos los diferentes programas de TV por número de serie. Luego tengo lo mismo para los episodios, Episodio 01, Episodio 02, etc. Lo que me gustaría es que al mostrar una lista de todos los episodios, estos se ordenen por episodio y serie. Analizaré entonces los metadatos y campos personalizados. Gracias Otto.

@yeope tu taxonomía debería ser "series" y tus términos deberían ser serie 1, serie 2, etc. Con los episodios, asumo que una serie contiene múltiples episodios, por lo que podría usar la misma taxonomía "series" y si son jerárquicos, entonces episodio 1, episodio 2, etc. tendrían el término padre "serie x". Luego podrías consultar una serie completa en orden con los episodios apareciendo donde deberían.

@Chris_O Entiendo, ¡puede que tengas razón ahí! El único problema que veo es el hecho de tener que repetir los términos "Episodio 1", "Episodio 2" para cada serie. También no poder agrupar todos los episodios 1 independientemente de la serie, pero creo que probablemente haya una solución. Gracias Chris_O

Usar una taxonomía para episodios en realidad no tiene mucho sentido, porque la agrupación no sirve. Piensa en esto: si tienes "episodio 1" como término, entonces estás agrupando el episodio 1 con todos los demás episodios 1 de cualquier otro programa de TV. Los números de episodio y serie tienen más sentido como post_meta, porque son específicos para ese programa en particular y no son útiles como grupo. El nombre del programa de TV sería útil como término en una taxonomía de tv-show, porque así agrupas todo el programa junto.

Pero una taxonomía para series medio funciona, pero solo porque agrupa los programas en una temporada o algo similar, aunque tendrías que consultarla junto con la taxonomía tv-show. En dicha taxonomía de series, tus términos serían 1, 2, 3, que representan el número de temporada del programa. Pero aun así preferirías esta información como postmeta, ya que querrás ordenar por ella. Y como también puedes consultar postmeta, no tiene mucho sentido duplicarla como taxonomía.

@Otto, al final terminé usando campos personalizados :) Tenía más sentido.

Otto siguió esto con una interesante publicación en el blog: Cuándo (no) usar una Taxonomía Personalizada.

@otto Gracias por compartir esto, es realmente bueno leer un poco más sobre taxonomías y sus usos. Específicamente estoy interesado en conocer tus pensamientos sobre una situación como la descrita en la publicación Columnas de Taxonomía Ordenables. ¿Cuál sería la mejor solución cuando quiero poder consultar todas las publicaciones en un rango de colores, pero también quiero ordenar por color? Tal vez esto sería mejor como una pregunta separada...

Si quieres ordenar por ello, entonces realmente debería ser meta en lugar de una taxonomía. Ordenar por taxonomía no tiene mucho sentido, en realidad.

Gracias @Otto. Aunque no estoy de acuerdo con tu afirmación: "Sin embargo, si tienes que recurrir a hacer este tipo de cosas, entonces tu estructura de diseño de datos está mal desde el principio"... Podría ser útil poder reordenar la lista de entradas por término de categoría en el lado del administrador...

@ClemC Eso no tiene mucho sentido. Las entradas pueden tener múltiples categorías. ¿Por qué criterio estás ordenando? ¿Cuál es tu criterio de ordenación secundario cuando dos entradas tienen la misma categoría? Ese es el tipo de problema con el que te encuentras, las taxonomías son solo agrupaciones, el "término" es solo una cara bonita de esa agrupación, no es la parte importante. La parte importante es el grupo en sí. No ordenarías nombres de animales alfabéticamente por su taxonomía linneana. No te ayuda en nada.

Hola @Otto, tienes razón. Tomé como referencia el caso de mi proyecto actual que es bastante particular... Un CPT (película) que permite solo un único término de una taxonomía personalizada (festival) con botones de radio para su selección. El orden predeterminado de la lista de CPT es por término (festival) que en este caso particular tiene suficiente lógica, ¿no? No se me ocurre un mejor enfoque sobre el "diseño de datos"... He implementado "festivales" como una taxonomía porque los únicos datos que necesitan son su descripción y agrupa lógicamente "películas". PD: Perdón por mi inglés.

Sí, es justo, pero entonces es un grupo. Estás agrupando cosas juntas. ¿Qué significa "ordenar por" en ese contexto? Si tienes un montón de cosas en el mismo grupo, entonces puedes "seleccionar por" ese grupo, y eso tiene sentido, pero "ordenar" es algo totalmente diferente. Ordenas por campos que tienen valores diferentes, no por campos que tienen todos los mismos valores.

Lo siento @Otto, solo ahora noto tu respuesta... Estoy totalmente de acuerdo con tus puntos semánticos y lógica. Pero en mi contexto, "ordenar por" sería principalmente una cuestión ergonómica. Agrupar visualmente las proyecciones por "festival" puede ayudar importante al usuario a obtener un resumen visual basado en el factor más importante para él, esto de un vistazo. Por lo tanto, no estoy seguro de poder lograr esto de otra manera que no sea "ordenando", lo cual reconozco que no es un término apropiado...

Llego un poco tarde a esto, pero hay una forma más simple y más al estilo WordPress de hacerlo.
Construye tu tax_query como de costumbre.
$tax_query = array();
$tax_query['relation']="OR";
$tax_query[] = array(
'taxonomy' => 'product_cat', // Taxonomía de categoría de producto
'field' => 'slug', // Campo a usar (slug)
'terms' => $cat_terms, // Términos a incluir
);
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; // Página actual
Configura tus argumentos para query_posts o WP_Query
$args = array(
'post_type'=>'post', // Tipo de post
'posts_per_page'=>12, // Posts por página
'paged'=>$paged, // Paginación
'tax_query' => $tax_query, // Query de taxonomía
);
Antes de hacer tu llamada query_posts / WP_Query, engancha el filtro orderby y sobrescríbelo
add_filter('posts_orderby', 'edit_posts_orderby');
function edit_posts_orderby($orderby_statement) {
$orderby_statement = " term_taxonomy_id ASC "; // Ordenar por ID de taxonomía ascendente
return $orderby_statement;
}
query_posts($args);
remove_filter('posts_orderby', 'edit_posts_orderby'); // No olvides remover el filtro después
No olvides remover el filtro después...
Esto funciona porque tax_query crea los joins necesarios, solo necesitas ordenar por uno de los campos del join.

¿Alguna idea sobre cómo ordenar por nombre en lugar de term_taxonomy_id? Cambiar term_taxonomy_id en orderby_statement genera errores

@tehlivi este método no funciona para ordenar por nombre porque el nombre está en la tabla wp_terms
. WordPress parece almacenar en caché los términos de taxonomía, así que incluso si tu consulta de taxonomía busca por slug o nombre, que también están en la tabla wp_terms
, WordPress los procesa a través de su lista en caché y los intercambia por IDs almacenados en term_relationships.term_taxonomy_id
, por lo que no tiene que consultar la tabla wp_terms
como parte de la consulta principal. Lo que significa que ni el nombre ni el slug están incluidos en la consulta SQL resultante. Tienes que añadir joins.

@EthanC oye hombre, gracias por tu respuesta detallada, y espero que si alguien encuentra esto en el futuro, encuentre útil tu respuesta. Pero para mí, ciertamente es difícil recordar algo de 2016. creo que terminé pasando el array por una función de ordenación después de que la consulta se completara. Estoy seguro de que cualquier desarrollador que tomó ese proyecto después de que dejé la compañía me odia. Ja.

@tehlivi Sí, terminé ignorando la consulta principal por completo en caso de que algunos posts tuvieran asignados más de un término. Opté en su lugar por ejecutar get_terms()
y luego get_posts
para cada término. Añadió ~15 consultas a la carga de la página, pero le dio al diseñador el resultado que quería.

No estoy seguro de por qué todas las soluciones aquí son exageradas. OK, fue hace medio siglo, pero actualmente estoy ejecutando el siguiente código y funciona:
<?php // Por defecto
$wheels_args = array(
'post_type' => 'wheels',
'posts_per_page' => '96',
'orderby' => 'taxonomy, name', // Solo ingresa 2 parámetros aquí, separados por coma
'order'=>'ASC'
);
$loop = new WP_Query($wheels_args);
?>
Esto ordenará las taxonomías de tu CPT primero por su taxonomía en orden alfabético y dentro de estos grupos de taxonomía también por orden alfabético.

@yeope ¿Por qué esta es la respuesta aceptada? Gracias a Dios que seguí bajando

No pude hacer que esto funcione. ¿Puedes señalar un sitio con alguna explicación sobre eso? no hay nada aquí, que respalde tu código

No se analiza correctamente, especialmente con esta coma, y es ignorado por WP (6.x).

Bueno, me gustaría compartir mi experiencia ordenando tipos de contenido personalizados (custom post types) por categoría/taxonomía.
EL SITIO WEB
- Un sitio web de una agencia de viajes basado en WordPress
- Contenido principal en un tipo de contenido personalizado llamado 'ruta'
- Taxonomía con esta estructura: Tipo-de-viaje > continente > país
EL CASO
En las páginas de archivo de categorías, el cliente quería que las publicaciones se ordenaran:
- Por continente, ordenados por número de rutas en cada uno.
- Por país, ordenados alfabéticamente.
LOS PASOS
Primero, capturé la consulta de la página de archivo sin modificar, que resultó ser así:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) )
AND wp_posts.post_type IN ('ruta', 'nav_menu_item')
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45
AND wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC LIMIT 0, 20
Segundo, modifiqué el código SQL en Sequel Pro contra la base de datos para adaptarlo a mis necesidades. Obtuve esto (sí, probablemente se puede mejorar: mi conocimiento de MySQL no es excelente):
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID, tt1.parent AS pare,
(
SELECT COUNT(*)
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id = tt1.term_taxonomy_id )
WHERE 1=1
AND tt1.parent = pare
) AS Total
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) )
AND wp_posts.post_type IN ('ruta', 'nav_menu_item')
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45
AND wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY
total DESC,
wp_terms.name
Tercero, enganché la consulta en el archivo functions.php con tres filtros: posts_fields, posts_join y posts_orderby
El código en functions.php:
function xc_query_fields( $fields ) {
$fields = "wp_posts.ID, wp_posts.post_title, wp_terms.name, tt1.parent AS pare,
(
SELECT COUNT(*)
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id = tt1.term_taxonomy_id )
WHERE 1=1
AND tt1.parent = pare
)
AS Total";
return $fields;
}
function xc_query_joins( $join ) {
$join .= "INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )";
return $join;
}
function xc_query_orderby( $join ) {
$join = "total DESC, wp_terms.name ";
return $join;
}
Finalmente activé los filtros desde el hook pre_get_post según algunas condiciones
function filtra_queries( $query )
{
if ( is_archive() && $query->is_main_query() && !is_admin() ) {
$rutes = array('viajes-privados', 'asia', 'africa', 'oceania', 'america', 'oriente-proximo');
if ( in_array( $query->get('category_name'), $rutes ) )
{
add_filter( 'posts_fields', 'xc_query_fields' );
add_filter( 'posts_join', 'xc_query_joins' );
add_filter( 'posts_orderby', 'xc_query_orderby' );
}// end if in_array
}// end if is_archive
}
add_filter('pre_get_posts', 'filtra_queries');
Espero que esto pueda ayudar a alguien

Tuve un problema muy similar al que enfrenté: quiero ordenar un archivo de tipo de publicación personalizada (artículos de revista) por una taxonomía personalizada (números). Nunca hago consultas SQL directas en mi sitio - y usualmente si estás como estas otras respuestas - necesitas reconsiderar tu enfoque.
PROBLEMAS:
1) WordPress no te permite ordenar taxonomías de manera inteligente.
2) WordPress simplemente no permite que orderby
use taxonomías en WP_Query para tipos de publicación (como lo explica Otto).
SOLUCIONES:
1) Ordenar taxonomías se logra mejor actualmente con el plugin Custom Taxonomy Order NE. Te permite ordenar la taxonomía mediante un editor WYSIWYG en wp-admin
, lo cual no es como yo lo haría pero no he encontrado nada mejor.
Cuando configures el plugin, obtendrás algo similar a lo que he hecho aquí. Toma nota de la opción Auto-sort Queries of this Taxonomy
- configúrala como Custom Order as Defined Above
; esto te dará el orden que necesitas. Captura de pantalla:
2) Con una taxonomía ordenada en su lugar, ahora puedes crear una serie de llamadas WP_Query que recorran cada término, creando efectivamente un archivo ordenado por la taxonomía. Usa get_terms()
para crear un array de todos los términos de la taxonomía, luego ejecuta un foreach
sobre cada término. Esto crea un WP_Query
para cada término que devolverá todas las publicaciones para un término dado, creando efectivamente un archivo ordenado por término de taxonomía. Código para hacer que esto ocurra:
// Obtén tus términos y ponlos en un array
$issue_terms = get_terms([
'taxonomy' => 'issues',
'hide_empty' => false,
]);
// Ejecuta foreach sobre cada término para configurar la consulta y mostrar las publicaciones
foreach ($issue_terms as $issue_term) {
$the_query = new WP_Query( array(
'post_type' => 'post',
'tax_query' => array(
array(
'taxonomy' => 'issues',
'field' => 'slug',
'terms' => array( $issue_term->slug ),
'operator' => 'IN'
)
)
) );
// Ejecuta el loop sobre cada consulta
while($the_query->have_posts()) :
$the_query->the_post();
// TU SALIDA DE PLANTILLA PARA CADA PUBLICACIÓN
endwhile;
}
Lectura relacionada en este sitio: Mostrar todas las publicaciones en un tipo de publicación personalizada, agrupadas por una taxonomía personalizada

Aquí está la solución que he utilizado para este problema en particular. Esta solución es para casos extremos donde no es posible usar un filtro pre_get_posts
y ya existe una paginación en la consulta (por ejemplo: WooCommerce):
global $wpdb;
$taxonomies = array('my-tax-1', 'my-tax-2', 'my-tax-3');
$orderby = "'".implode("', '", array_keys($taxonomies))."'";
$id_sql = $GLOBALS['wp_query']->request;
$id_sql = preg_replace('/LIMIT\s+\d+\s?,?\s\d*/', '', $id_sql);
$id_sql = str_replace('SQL_CALC_FOUND_ROWS', '', $id_sql);
$term_sql = "SELECT
tt.taxonomy AS `taxonomy`,
t.name AS `term_name`,
t.slug AS `term_slug`,
count(*) AS `term_count`
FROM ({$id_sql}) p
JOIN wp_term_relationships tr
ON p.ID = tr.object_id
JOIN wp_term_taxonomy tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id
JOIN wp_terms t
ON tt.term_id = t.term_id
WHERE tt.taxonomy IN ({$orderby})
GROUP BY t.slug
ORDER BY
FIELD(tt.taxonomy, {$orderby})"; // Añade aquí un ordenamiento más específico si es necesario
$results = $wpdb->get_results($term_sql, ARRAY_A);
He utilizado esto para crear un menú de navegación ordenado por taxonomía, término y conteo de publicaciones por término.
Si solo quieres las publicaciones, cambia la consulta a SELECT p.*
y GROUP BY p.ID

Me gusta ordenar mis términos manualmente, así que uso un plugin para hacerlo. Y soy fan del filtro pre_get_posts
, así que tomé el ejemplo funcional de Drew Gourley y lo adapté para que funcione con eso. Este es un caso algo especial, pero lo comparto por si ayuda a alguien. El siguiente código va en functions.php o en un plugin personalizado.
Primero comencemos con el filtro. Ordenamos el tipo de publicación personalizado music
por la taxonomía personalizada style
:
function so14306_pre_get_posts($query)
{
if (is_admin()) :
return;
endif;
if ($query->is_main_query()) :
if (is_post_type_archive('music')) :
$query->set('orderby', 'style');
endif;
endif;
}
add_action('pre_get_posts', 'so14306_pre_get_posts');
Luego llamamos al filtro post_clauses:
function so14306_posts_clauses($clauses, $wp_query)
{
global $wpdb;
if (isset($wp_query->query_vars['orderby']) && $wp_query->query_vars['orderby'] === 'style') {
$orderby = $wp_query->query_vars['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 = '{$orderby}' OR taxonomy IS NULL)";
$clauses['groupby'] = "object_id";
$clauses['orderby'] = "GROUP_CONCAT({$wpdb->terms}.term_order ORDER BY {$wpdb->terms}.term_order ASC) ASC";
$clauses['orderby'] .= ", {$wpdb->posts}.post_name ASC";
}
return $clauses;
}
add_filter('posts_clauses', 'so14306_posts_clauses', 10, 2);
Ahora todo lo que necesitas hacer es ordenar tus taxonomías con el siguiente plugin: Simple Custom Post Order. Este plugin es obligatorio para esta solución, ya que añade la columna term_order
a la base de datos.
Y esta línea:
$clauses['orderby'] .= ", {$wpdb->posts}.post_name ASC"
ordena las publicaciones por título, así que el ordenamiento completo de la solución anterior es: término de taxonomía => título de publicación.

Muchas gracias, esto es muy útil. Es genial tener una forma de ordenar visualmente. ¿Sabes por qué está la parte "OR taxonomy IS NULL"? Parece algo que no es necesario.

Muestra el primer término correctamente, pero después de esas publicaciones el siguiente término no sigue lógicamente el orden del menú como está establecido con SCP Order. Me pregunto si es porque estoy intentando hacerlo con productos, y WooCommerce ya tiene un orden de atributos...quizás los dos están en conflicto. En la base de datos, sin embargo, los IDs en la columna term_order son correctos...

Una forma bastante sencilla de hacer esto es agregar una función que:
- Cuando tu publicación sea publicada...
- Obtener el ID/slug/etc de tu categoría...
- Guardarlo como un valor meta personalizado para tu publicación
Y luego, en tu loop, ordenar tus publicaciones por ese valor meta.
Entonces:
// 1
add_action( 'publish_post', 'save_and_add_meta' );
function save_and_add_meta($post_id){
//Eliminar temporalmente la acción para evitar un bucle infinito
remove_action( 'publish_post', 'save_and_add_meta' );
// 2
$category_slug = get_the_terms($post_id, 'your_taxonomys_name')[0]->slug;
//3
add_post_meta($post_id, 'cat_slug', $category_slug);
//Agregar la acción nuevamente
add_action( 'publish_post', 'save_and_add_meta' );
}
Luego en tu consulta de WP agrega en tus $args:
'meta_key' => 'cat_slug',
'orderby' => 'meta_value',
'order' => 'DESC',
Esto funciona si puedes encontrar una manera de restringir a los usuarios a asignar solo una categoría por publicación, o si tus categorías son mutuamente excluyentes. Si asignan más de una categoría, sin embargo, la publicación se dejaría fuera de una de ellas.

Es como una consulta antes de la consulta, pero no molestará si no estamos consultando demasiadas publicaciones... La idea es modificar la consulta principal para que ni siquiera necesitemos ir a las plantillas y generar nuevas consultas y bucles...
function grouped_by_taxonomy_main_query( $query ) {
if ( $query->is_home() && $query->is_main_query() ) { // Solo se ejecuta en la página de inicio
$post_ids = array();
$terms = get_terms('my_custom_taxonomy');
foreach ( $terms as $term ) {
$post_ids = array_merge( $post_ids, get_posts( array(
'posts_per_page' => 4, // como desees...
'post_type' => 'my_custom_post_type', // Si es necesario... Por defecto son entradas
'fields' => 'ids', // solo queremos los IDs para usarlos luego en 'post__in'
'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // obteniendo publicaciones en el término actual
);
}
$query->query_vars['post_type'] = 'my_custom_post_type'; // Nuevamente, si es necesario... Por defecto son entradas
$query->query_vars['posts_per_page'] = 16; // Si es necesario...
$query->query_vars['post__in'] = $post_ids; // Filtramos con los IDs de publicaciones obtenidos anteriormente
$query->query_vars['orderby'] = 'post__in'; // Aquí mantenemos el orden generado en el bucle de términos
$query->query_vars['ignore_sticky_posts'] = 1; // Si no quieres que tus publicaciones fijas cambien el orden
}
}
// Engancho mi función anterior a la acción pre_get_posts
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );

Esto fallará, no puedes usar get_posts o WP_Query dentro de pre_get_posts, creará un bucle infinito. Porque cuando usas get_posts o WP_Query, se activará el hook pre_get_posts y esto causará un bucle infinito, incluso si verificas is_main_query, no se detendrá y seguirá ejecutándose continuamente.

Algunas respuestas son bastante complejas, escribí esta solución que es bastante básica de entender (creo/espero):
$args = array( 'post_type' => 'Teammember','posts_per_page' => -1);
$loop = new WP_Query($args);
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) {
$loop->the_post();
$id = get_the_id();
$name = get_the_terms( get_the_ID(), 'teammember-category' );
$sort[$id] = $name[0]->name;
}
}
wp_reset_postdata();
asort($sort);
$result = array_keys($sort);
Ahora la variable $result
contiene todos los IDs de los posts, ordenados ascendentemente por el nombre de la taxonomía personalizada.
Precaución: si un post contiene múltiples categorías, se necesita una solución diferente.
Puedes usar los IDs en una función foreach, algo así:
foreach($result as $id){
$image = get_the_post_thumbnail($id);
...etc.
}
o puedes hacer una segunda consulta como esta:
$loopnew = new WP_Query(array('post_type' => 'Teammember','post__in'=> $result));
if ( $loopnew->have_posts() ) {
while ( $loopnew->have_posts() ) {
$loopnew->the_post();
...etc.
}
}

Es un poco molesto que WordPress no te permita hacer eso y te obligue a tener básicamente dos campos con la misma información..
PERO aquí comparto mi solución. La idea es pasar todos los términos de taxonomías seleccionados a la información meta del post.
(Ten cuidado, necesitarás ajustarlo si tu taxonomía permite múltiples valores)
//agrega este hook para guardar automáticamente los términos como metadatos del post cuando guardas un post
add_action('save_post', 'add_custom_taxonomies_as_post_meta', 10, 1);
function add_custom_taxonomies_as_post_meta($id)
{
$current_post = get_post($id);
$taxonomies = get_object_taxonomies($current_post);
foreach ($taxonomies as $tax) {
$post_terms = get_the_terms($id, $tax);
$term = $post_terms[0];
add_post_meta($id, $tax, $term->name, true);
}
}
Después de colocar esto en tu functions.php puedes usar meta_key y orderby como siempre para ordenar tus posts así:
'meta_key' => TU-TAXONOMIA,
'orderby' => array(
'meta_value' => 'ASC'
)
Espero que esto sea útil para alguien.
