Usando wp_query, ¿es posible ordenar por taxonomía?

49

Mi pregunta es simple, estoy usando WP_Query para recuperar algunas publicaciones de tipo personalizado filtradas por una taxonomía usando tax_query.

Ahora mi problema es que me gustaría ordenar por taxonomía, pero desde la documentación y la búsqueda en la web no puedo encontrar una solución.

El orden en WP_Query le permite ordenar por un grupo de campos, incluso metacampos personalizados, pero no parece admitir taxonomía.

¿Algún indicador en la dirección correcta?

Gracias a todos.

yeope
fuente

Respuestas:

12

No, no es posible ordenar por taxonomía, porque desde cierto punto de vista, eso no tiene mucho sentido.

Las taxonomías son formas de agrupar cosas. Entonces, el punto de tener una taxonomía en las publicaciones sería tener términos en esa taxonomía que se compartan entre las publicaciones. Si una taxonomía tuviera términos que solo se usaran en una publicación cada uno, entonces la taxonomía sería algo inútil. Y si los términos se compartieran como deberían ser, ordenarlos no produciría nada particularmente útil.

Lo que deberías estar usando en tal situación es el post meta. Puede ordenar por meta meta, y es único para cada publicación.

Editar: Dicho esto, puede ordenar por taxonomía haciendo una consulta SQL personalizada utilizando un filtro, simplemente no puede hacerlo desde una WP_Query no modificada: http://scribu.net/wordpress/sortable-taxonomy-columns.html

Sin embargo, si tiene que recurrir a hacer este tipo de cosas, entonces su estructura de diseño de datos es incorrecta en primer lugar. Los "términos" en la taxonomía no son "datos" reales. Los términos en sí no tienen un significado inherente, son solo etiquetas para la agrupación particular que están describiendo. Si los trata como datos significativos, entonces tiene un defecto de diseño subyacente.

Las taxonomías agrupan cosas asignándoles términos. Esa agrupación es el objetivo de las taxonomías, los términos son solo caras bonitas en la agrupación. Si tiene metadatos significativos para asignar a una publicación, entonces debería usar el meta de la publicación para ello. Y que puede ordenar por, porque la meta meta utiliza claves y valores para almacenar información. Con una taxonomía, en realidad solo está almacenando claves, y sus valores son las publicaciones agrupadas por ese término.

Las cosas son más fáciles a largo plazo si usas el enfoque correcto para ello. Si bien no digo que no puedas hacer algo extraño con la taxonomía, a la larga solo te estás haciendo las cosas más difíciles al usarla incorrectamente.

Otón
fuente
Hola Otto, gracias por la respuesta. Veo tu punto y tal vez estoy yendo por el camino equivocado con esto. En mi ejemplo, un sitio de programas de televisión, tengo taxonomía para la serie 1, serie 2, serie 3, etc. Así que puedo agrupar todos los diferentes programas de televisión por número de serie. Luego tengo lo mismo para los episodios, Episodio 01, Episodio 02, etc. Lo que me gustaría es mostrar una lista de todos los episodios ordenados por episodio y serie. Analizaré y luego publicaré meta y campos personalizados. Gracias Otto
yeope
@yeope, su taxonomía debe ser serie y sus términos deben ser serie 1, serie 2, etc. Con los episodios, supongo que una serie contiene varios episodios, por lo que podría usar la misma taxonomía, "serie" y, si son jerárquicos, el episodio 1, el episodio 2, etc. tendría el término padre "serie x". Luego, puede consultar una serie completa en orden con los episodios en línea donde deberían.
Chris_O
@Chris_O Ya veo, ¡podrías estar ganando dinero allí! El único problema que puedo ver es el hecho de tener que repetir los términos "Episodio 1", "Episodio 2" para cada serie. Además, no puedo agrupar todos los episodios 1 sin depender de la serie, pero creo que probablemente hay una forma de evitarlo. Gracias Chris_O
yeope
2
Usar una taxonomía para episodios no tiene mucho sentido, en realidad, porque la agrupación no tiene valor. Piénselo, si tiene "episodio 1" como término, entonces está agrupando el episodio 1 con cada otro episodio 1 de cualquier otro programa de televisión. Los números de episodios y series tienen más sentido como post_meta, porque son específicos de ese programa en particular y no son útiles como grupo. El nombre del programa de televisión sería útil como un término en una taxonomía de un programa de televisión, porque entonces estás agrupando el programa como un todo.
Otto
1
Otto siguió esto con una publicación de blog interesante: Cuándo (no) usar una Taxonomía personalizada .
Jan Fabry
47

La respuesta aceptada para esta pregunta es inaceptable. Es ilógico suponer que ordenar por impuestos "no tiene sentido". La respuesta que dio no tiene sentido.

Considere tener un tipo de publicación de menú. Entonces tiene un impuesto personalizado de "FoodCategories". El impuesto FoodCategories tiene los términos "Desayuno", "Almuerzo" y "Cena". Si envía una consulta utilizando el parámetro tax_query, ahora tiene un conjunto de resultados con todos los términos, sin embargo, están ordenados por fecha de publicación.

Para obtener el orden correcto de estos, en relación con sus términos, y luego mostrarlos en el front-end apropiadamente separando las publicaciones en sus diversas categorías, debe recorrer el conjunto de resultados, luego consultar cada publicación individual dentro del conjunto de resultados para encontrar sus términos y compararlos con el término actual, filtrar en una matriz y continuar durante todo el proceso. Luego debe volver a recorrer la nueva matriz para mostrarla. Esto no es productivo.

Sería bueno que WP tuviera una opción de pedido "tax__in", ya que tiene una opción "post__in", pero como no la tiene, debe realizar el ridículo proceso anterior; personalice la consulta usted mismo mediante el filtro 'posts_orderby' y el filtro 'posts_join' para ajustar el método orderby y agregar el término al conjunto de resultados, respectivamente; o tiene que hacer una nueva consulta para cada término que está filtrando dentro de las secciones html relativas a esos términos.

Lo más eficiente sería cambiar la cadena de consulta por medio de filtros. Lo más fácil sería hacer tres consultas separadas. La API de WP debe manejar los pedidos por impuestos o cualquier parámetro de consulta restrictivo. Si está restringiendo una consulta basada en ciertas condiciones, existe una alta probabilidad de que muchos tengan que ordenar por esas mismas condiciones.

Aryan Duntley
fuente
2
Perdón, pero estas equivocado. Ordenar por taxonomía tampoco tiene ningún sentido en su caso. Que quieres mostrar ¿Todos los desayunos primero, seguidos de todas las cenas, luego todos los almuerzos? Debe seleccionar lo que desea y el orden en que lo desea, pero la taxonomía es solo una etiqueta de agrupación. No son "datos" significativos por los que debe ordenar. Si es así, entonces no debería ser un término en una taxonomía, en su lugar, debe convertirlo en un meta-meta.
Otto
15
Vamos, por supuesto que habrá algunos casos en los que querrás ordenar publicaciones por término de taxonomía. Otro ejemplo es un tipo de publicación de película con una taxonomía de calificación. En una lista de películas, es muy fácil imaginar a las personas que desean ordenar una lista de películas por clasificación, de modo que todas las películas con clasificación G, clasificación PG, etc., aparecen en la parte superior. (En este y en el ejemplo de la comida, podrían ordenarse por term_id en lugar de nombre). Hay una gran área gris de casos en los que probablemente sea mejor servido por una taxonomía y no por una meta, pero probablemente también sea útil que esa taxonomía se ordene -poder.
SeventhSteel
2
Las clasificaciones de PG y G son una buena opción de taxonomía, excepto que son datos sobre películas específicas. Por lo tanto, son meta. Son datos, no categorías. Solo tener un número limitado de opciones no hace una taxonomía. Si necesita ordenar por, entonces hágalo meta o fuerce la clasificación por taxonomía mediante un código específico de taxonomía. Por cierto, NC17 viene después de PG. Por lo tanto, necesita un código para hacer ese pedido de todos modos.
Otto
Sé que llego tarde a la fiesta con este comentario, pero me topé con esto. Ordenar por taxonomía puede tener sentido en algunas situaciones. Tenemos listados de trabajo en un proyecto como tipo de publicación y luego el Estado y la Ciudad en los que se encuentra el trabajo son taxonomías. Queremos que sean fácilmente grupables (mostrar todos los trabajos en un estado o mostrar todos los trabajos en una ciudad) para que la taxonomía sea la mejor solución. Al mismo tiempo, hay una búsqueda general de trabajo donde queremos ordenarlos primero por título, luego por estado y luego por ciudad.
Dennis Puzak
Otro caso de uso: un cliente tiene un montón de artículos, cada uno de los cuales tiene una categoría. El cliente quiere que haya una página que enumere todos los artículos, que se pueden ordenar alfabéticamente, por fecha o por categoría. Las categorías también se pueden filtrar, pero enumerar alfabéticamente todos los artículos por categoría no es una locura de un caso de uso y ves que aparece con bastante frecuencia.
Wilson Biggs
15

Sí, pero está bastante involucrado ...

Agregue a functions.php en su 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 se basa en algunas cosas encontradas y algunas cosas que hice yo mismo. Explicar es bastante difícil, pero la conclusión es que con esto en ejecución, puede poner? Orderby = (taxonomy query var) & order = ASC (o DESC) y ella comenzará de inmediato.

Drew Gourley
fuente
Gracias Drew, intentaré ejecutar ese SQL, necesito editar un poco, pero podría funcionar. Mi único problema ahora, es que podría estar yendo en las direcciones equivocadas como lo señaló Otto. Gracias Drew EDITAR: no es necesario editar. Puedo ver dónde necesita el ajuste :) Gracias
yeope
Si lo agarró en los últimos dos minutos, no funcionará, adelante y agárrelo ahora, lo arreglé. Se configuró para dos taxonomías específicas, mejoré el código para trabajar en todas las taxonomías registradas.
Drew Gourley
Gracias otra vez. Por si acaso probé su solución y funciona. Además, si alguien más quiere usarlo, debe cambiar add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );a add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );Gracias :)
yeope
Sí, esto ahora está arreglado en el bloque de código, tomé esto de un proyecto en el que estoy trabajando y olvidé cambiar el nombre de la función a pesar de que lo cambié en el gancho.
Drew Gourley
1
¿Sabes si es posible ordenar las taxonomías por ID en lugar del nombre? Estoy tratando de obtener el mismo resultado ordenando los grupos de taxonomía por ID
Javier Villanueva
9

Llego tarde al juego aquí, pero hay una manera más simple de hacer esto en WordPressy.

Desarrolle su consulta de impuestos como de costumbre.

$tax_query = array();
$tax_query['relation']="OR";
$tax_query[] = array(
    'taxonomy' => 'product_cat',
    'field'    => 'slug',
    'terms'    => $cat_terms,
);
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

Configure sus argumentos para query_posts o WP_Query

$args = array(
    'post_type'=>'post',
    'posts_per_page'=>12,
    'paged'=>$paged,
    'tax_query' => $tax_query,
);

Antes de realizar su consulta query_posts / WP_Query, conéctese al filtro de pedido y anúlelo

add_filter('posts_orderby', 'edit_posts_orderby');
function edit_posts_orderby($orderby_statement) {
    $orderby_statement = " term_taxonomy_id ASC ";
    return $orderby_statement;
}
query_posts($args);
remove_filter('posts_orderby', 'edit_posts_orderby');

no olvides quitar el filtro después ...

esto funciona b / c tax_query crea las combinaciones, etc. para usted, solo necesita ordenar por uno de los campos de la combinación.

Francis Yaconiello
fuente
2
¿Alguna idea sobre cómo ordenar por nombre en lugar de term_taxonomy_id? cambiar term_taxonomy_id en orderby_statement arroja errores
tehlivi
¡Esta es la respuesta correcta para cualquiera que esté interesado!
Mayra M
2

Bueno, me gustaría exponer mi experiencia en la clasificación de tipos de publicaciones personalizadas por categoría / taxonomía.

LA WEB

  1. Un sitio web de agencia de viajes que se ejecuta en WordPress
  2. Contenido principal en el tipo de publicación personalizada llamada 'ruta'
  3. Taxonomía con esta estructura Tipo de viaje> continente> país

EL CASO

En las páginas de la lista de categorías de archivo, el cliente quería que las publicaciones se clasificaran por

  1. El continente, ordenado por número de rutas en cada una.
  2. El país, ordenado alfabéticamente.

LOS PASOS

Primero , capto la solicitud de la consulta de la página de archivo no modificada 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

En segundo lugar , edité el código sql en Sequel Pro en la base de datos para satisfacer mis necesidades. Salí con esto (sí, probablemente se pueda mejorar: mi conocimiento en MySQL no es sobresaliente):

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  

En tercer lugar , 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 del gancho pre_get_post de acuerdo con 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

Xavier Caliz
fuente
Buen trabajo, ridículo que se toma esta cantidad de código para ordenar algo por una taxonomía. Gran problema con WP.
serraosays
2

Tuve un problema muy similar con el que me ocupé: quiero ordenar un archivo de post-tipo personalizado (artículos de revistas) por una taxonomía personalizada (números). Nunca hago consultas directas de SQL en mi sitio, y generalmente si eres como estas otras respuestas, debes repensar tu enfoque.

PROBLEMAS:

1) Wordpress no le permite ordenar taxonomías de manera inteligente.

2) Wordpress simplemente no permite orderbyutilizar taxonomías en post-type WP_Query (como lo explica Otto).

SOLUCIONES

1) La ordenación de taxonomías se logra mejor con el complemento NE de orden de taxonomía personalizada en este momento. Le permite ordenar la taxonomía a través de WYSIWYG, wp-adminque no es como lo haría, pero no he encontrado nada mejor.

Cuando configure el complemento, obtendrá algo similar a lo que he hecho aquí. Tome nota de la opción Auto-sort Queries of this Taxonomy: establezca esto en Custom Order as Defined Above; esto le da el pedido que necesita. Captura de pantalla:

Orden NE de taxonomía personalizada

2) Con una taxonomía ordenada en su lugar, ahora puede crear una serie de llamadas WP_Query que se ejecutan a través de cada término, creando efectivamente un archivo ordenado por la taxonomía. Utilícelo get_terms()para crear una matriz de todos los términos fiscales, luego ejecute un foreachsobre cada término. Esto crea un elemento WP_Querypara cada término que devolverá todas las publicaciones para un término determinado, creando efectivamente un archivo ordenado por término de taxonomía. Código para que esto suceda:

  // Get your terms and put them into an array
  $issue_terms = get_terms([
    'taxonomy' => 'issues',
    'hide_empty' => false,
  ]);

  // Run foreach over each term to setup query and display for posts
  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'
        )
      )
    ) );

    // Run loop over each query
    while($the_query->have_posts()) :
      $the_query->the_post();

      // YOUR TEMPLATE OUTPUT FOR EACH POST

    endwhile;
  }

Lectura relacionada en este sitio: muestra todas las publicaciones en un tipo de publicación personalizada, agrupadas por una taxonomía personalizada

serraosayos
fuente
2

No estoy seguro de por qué todas las soluciones aquí son demasiado exageradas. OK, hace media década, pero actualmente estoy ejecutando el siguiente código y funciona:

   <?php // Default
    $wheels_args = array(
        'post_type' => 'wheels',
        'posts_per_page' => '96',
        'orderby' => 'taxonomy, name', // Just enter 2 parameters here, seprated by comma
        'order'=>'ASC'
    );
    $loop = new WP_Query($wheels_args);
    ?>

Esto ordenará las taxonomías de su CPT primero por su taxonomía en orden alfabético y dentro de estos grupos de taxonomía también por orden alfabético.

usuario3135691
fuente
@yeope ¿Por qué esta es la respuesta aceptada? gracias a dios me desplacé
Juan Solano
1

Aquí está la solución que he usado para este problema en particular. Esta solución es para casos extremos en los que no es posible usar un pre_get_postsfiltro y hay una paginación existente en la consulta (es decir: 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})"; // Add further specific ordering here

$results = $wpdb->get_results($term_sql, ARRAY_A);

Lo he usado para crear un menú de navegación ordenado por taxonomía, término y recuento de publicaciones por término.

Si simplemente desea las publicaciones, cambie la consulta a SELECT p.*yGROUP BY p.ID

CodeShaman
fuente
0

Es como una consulta antes de la consulta, pero no molestará si no consultamos demasiadas publicaciones ... La idea es modificar la consulta principal para que ni siquiera necesitemos ir a plantillas y generar nuevas consultas y bucles ...

function grouped_by_taxonomy_main_query( $query ) {

    if ( $query->is_home() && $query->is_main_query() ) { // Run only on the homepage

        $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, // as you wish...
                'post_type' => 'my_custom_post_type', // If needed... Default is posts
                'fields' => 'ids', // we only want the ids to use later in 'post__in'
                'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // getting posts in the current term
            );
        }

        $query->query_vars['post_type'] = 'my_custom_post_type'; // Again, if needed... Default is posts
        $query->query_vars['posts_per_page'] = 16; // If needed...
        $query->query_vars['post__in'] = $post_ids; // Filtering with the post ids we've obtained above
        $query->query_vars['orderby'] = 'post__in'; // Here we keep the order we generated in the terms loop
        $query->query_vars['ignore_sticky_posts'] = 1; // If you dont want your sticky posts to change the order

    }
}

// Hook my above function to the pre_get_posts action
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );
Marcelo Viana
fuente