Usando wp_query, é possível solicitar por taxonomia?

49

Minha pergunta é simples, estou usando o WP_Query para recuperar algumas postagens de tipo personalizado filtradas por uma taxonomia usando tax_query.

Agora, meu problema é que eu gostaria de pedir pela taxonomia, mas a partir da documentação e pesquisa na Web não consigo encontrar uma solução.

O orderby em WP_Query permite que você encomende por vários campos, mesmo meta-campos personalizados, mas ele não parece suportar taxonomia.

Alguma indicação na direção certa?

Obrigado a todos.

yeope
fonte

Respostas:

12

Não, não é possível ordenar por taxonomia, porque, de um certo ponto de vista, isso não faz muito sentido.

Taxonomias são maneiras de agrupar as coisas. Portanto, o objetivo de ter uma taxonomia nas postagens seria realmente ter termos nessa taxonomia compartilhados entre as postagens. Se uma taxonomia tivesse termos que eram usados ​​apenas em um post cada, isso tornaria a taxonomia meio inútil. E se os termos fossem compartilhados como deveriam, então ordenar por ele não produziria nada de particularmente útil.

O que você deve usar em tal situação é a meta meta. Você pode encomendar por meta meta, e é exclusivo para cada postagem.

Edit: Dito isto, você pode solicitar por taxonomia, fazendo uma consulta SQL personalizada usando um filtro, você simplesmente não pode fazê-lo a partir de um WP_Query não modificado: http://scribu.net/wordpress/sortable-taxonomy-columns.html

No entanto, se você precisar recorrer a esse tipo de coisa, sua estrutura de design de dados estará errada em primeiro lugar. "Termos" na taxonomia não são "dados" reais. Os termos em si não têm significado inerente, são apenas rótulos para o agrupamento específico que estão descrevendo. Se você os estiver tratando como dados significativos, você tem uma falha de design subjacente.

As taxonomias agrupam as coisas atribuindo termos a elas. Esse agrupamento é o ponto principal das taxonomias, os termos são apenas rostos bonitos no agrupamento. Se você possui metadados significativos para atribuir a uma postagem, deve usar a meta da postagem para ela. E você pode pedir, porque o post meta usa chaves e valores para armazenar informações. Com uma taxonomia, você realmente está apenas armazenando chaves, com seus valores sendo as postagens agrupadas por esse termo.

As coisas ficam mais fáceis a longo prazo se você usar a abordagem correta para isso. Enquanto eu não estou dizendo que você não pode fazer algo estranho com a taxonomia, você está apenas tornando as coisas mais difíceis para si mesmo a longo prazo, usando errado.

Otto
fonte
Olá Otto, obrigado pela resposta. Entendo o seu ponto de vista e talvez eu esteja seguindo o caminho errado com isso. No meu exemplo, um site de programas de TV, tenho taxonomia para as séries 1, 2, 3, etc. Para agrupar todos os programas por número de série. Então, eu tenho o mesmo para episódios, Episódio 01, Episódio 02, etc. O que eu gostaria é de mostrar uma lista de todos os episódios que devem ser ordenados por episódio e série. Analisarei depois os campos meta e personalizados. Obrigado Otto.
yeope
@yeope sua taxonomia deve ser série e seus termos devem ser série 1, série 2 etc. episódio 2 etc teria o termo pai "série x". Depois, você pode consultar uma série inteira em ordem, com os episódios alinhados onde deveriam.
Chris_O
@ Chris_O eu vejo, você pode estar no dinheiro lá! O único problema que vejo é o fato de ter que repetir os termos "Episódio 1", "Episódio 2" para cada série. Também não ser capaz de agrupar todos os episódios 1, não dependendo da série, mas acho que provavelmente há uma maneira de contornar isso. Obrigado Chris_O
yeope
2
Usar uma taxonomia para episódios não faz muito sentido, na verdade, porque o agrupamento é inútil. Pense nisso, se você tiver "episódio 1" como termo, estará agrupando o episódio 1 com todos os outros episódios 1 de todos os outros programas de TV. Os números de episódios e séries fazem mais sentido como post_meta, porque são específicos a esse programa em particular e não são úteis como um grupo. O nome do programa de TV seria útil como um termo na taxonomia de um programa de TV, porque você estará agrupando o programa como um todo.
Otto
11
Otto seguiu isso com uma postagem interessante no blog: quando (não) usar uma taxonomia personalizada .
Jan Fabry
47

A resposta aceita para esta pergunta é inaceitável. É ilógico supor que ordenar por impostos "não faz sentido". A resposta que ele deu não faz sentido.

Considere ter um tipo de postagem no menu. Então você tem um imposto personalizado de "FoodCategories". O imposto FoodCategories tem os termos "Café da manhã", "Almoço" e "Jantar". Se você enviar uma consulta utilizando o parâmetro tax_query, agora terá um conjunto de resultados com todos os termos, mas eles serão ordenados por data de postagem.

Para obter a ordem correta deles, em relação aos termos deles, e depois exibir adequadamente no front-end, separando as postagens em suas várias categorias, você deve percorrer o conjunto de resultados e consultar cada postagem individual dentro do conjunto de resultados para encontrar seus termos e comparar com o termo atual, filtrar em uma matriz e continuar por toda parte. Em seguida, é necessário percorrer novamente a nova matriz para exibição. Isso não é produtivo.

Seria bom se o WP tivesse uma opção de pedido "tax__in" por uma opção "post__in", mas como não tem, você deve executar o processo ridículo acima; personalize você mesmo a consulta por meio dos filtros 'posts_orderby' e 'posts_join' para ajustar o método orderby e adicionar o termo ao conjunto de resultados, respectivamente; ou você deve fazer uma nova consulta para cada termo que você está filtrando nas seções html relativas a esses termos.

O mais eficiente seria alterar a string de consulta por meio de filtros. O mais fácil seria fazer três consultas separadas. A API do WP deve lidar com pedidos por impostos ou qualquer parâmetro de consulta restritivo. Se você estiver restringindo uma consulta com base em determinadas condições, há uma alta probabilidade de que muitos precisem solicitar pelas mesmas condições.

Aryan Duntley
fonte
2
Desculpe, mas você está errado. A ordenação por taxonomia também não faz sentido no seu caso. O que você quer mostrar? Primeiro todos os cafés da manhã, seguidos por todos os jantares e depois todos os almoços? Você deve selecionar o que deseja e a ordem em que deseja, mas a taxonomia é apenas um rótulo de agrupamento. Não são "dados" significativos que você deve solicitar. Se for, não deve ser um termo em uma taxonomia, você deve torná-lo um pós-meta.
Otto
15
Vamos lá, é claro que haverá alguns casos em que você desejará ordenar postagens por termo de taxonomia. Outro exemplo é um tipo de postagem de filme com uma taxonomia de classificação. Em uma lista de filmes, é muito fácil imaginar pessoas que desejam encomendar uma lista de filmes por classificação, para que todos os filmes com classificação G, PG, etc. apareçam na parte superior. (Neste exemplo e no exemplo da refeição, eles podem ser ordenados por term_id em vez de nome.) Há uma grande área cinza de instâncias em que você provavelmente é mais bem atendido por uma taxonomia e não por uma meta, mas provavelmente também é útil que essa taxonomia seja ordenada -capaz.
103015 SeventhSteel
2
As classificações PG e G são uma boa opção de taxonomia, exceto que são dados sobre filmes específicos. Assim, eles são meta. São dados, não categorias. Apenas ter um número limitado de opções não é uma taxonomia. Se precisar classificar por, faça-o meta ou force a classificação pela taxonomia via código específico da taxonomia. BTW, NC17 vem após PG. Portanto, você precisa de código para fazer esse pedido de qualquer maneira.
Otto
Eu sei que estou atrasado para a festa com este comentário, mas apenas esbarrei nisso. A ordenação por taxonomia pode fazer sentido em algumas situações. Temos listagens de trabalho em um projeto como um tipo de postagem e, em seguida, Estado e cidade em que o trabalho é taxonomias. Queremos que eles sejam facilmente agrupáveis ​​(mostrar todos os empregos em um estado ou mostrar todos os empregos em uma cidade), de modo que a taxonomia foi a melhor solução. Ao mesmo tempo, há uma pesquisa geral de empregos em que queremos classificá-las primeiro por título, depois por estado e depois por cidade.
Dennis Puzak
Outro caso de uso: um cliente possui vários artigos, cada um com uma categoria. O cliente deseja que exista uma página listando todos os artigos, que podem ser classificados em ordem alfabética, por data ou por categoria. As categorias também podem ser filtradas, mas listar todos os artigos por categoria em ordem alfabética não é tão louco para um caso de uso e você o vê aparecer com bastante frequência.
Wilson Biggs
15

Sim, mas é bastante envolvido ...

Adicione a functions.php no seu 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 );

Isso é frankenstein de algumas coisas encontradas e algumas coisas que eu mesmo fiz. Explicar é bastante difícil, mas o resultado final é com essa execução; você pode colocar? Orderby = (consulta de taxonomia var) & order = ASC (ou DESC) e ela decolará!

Drew Gourley
fonte
Obrigado Drew, vou tentar e tentar executar esse SQL, preciso editar um pouco, mas pode funcionar. Meu único problema agora é que posso estar indo na direção errada, como apontado por Otto. Obrigado Drew. Editar- Não há necessidade de editar eu posso ver onde ele precisa os ajustes :) Obrigado
yeope
Se você o pegou nos últimos dois minutos, não vai funcionar, vá em frente e pegue agora, eu consertei. Foi definido para duas taxonomias específicas; aprimorei o código para trabalhar em todas as taxonomias registradas.
Tirou Gourley
Agradeço novamente. Apenas no caso de eu tentar a sua solução e isso meio que funciona. Além disso, se alguém quiser usá-lo você precisa mudar add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );para add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );Obrigado :)
yeope
Sim, isso agora está corrigido no bloco de código. Tirei isso de um projeto em que estou trabalhando e esqueci de alterar o nome da função, mesmo que eu a tenha alterado no gancho.
Tirou Gourley
11
Você sabe se é possível solicitar as taxonomias por ID em vez do nome? Eu estou tentando obter o mesmo resultado encomendar os grupos de taxonomia por ID
Javier Villanueva
9

Estou chegando atrasado para o jogo aqui, mas há uma maneira mais simples e mais simples de fazer isso.

Crie sua consulta fiscal normalmente.

$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 seus argumentos para query_posts ou WP_Query

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

Antes de fazer sua chamada query_posts / WP_Query, conecte-se ao filtro orderby e substitua-o

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');

não esqueça de remover o filtro depois ...

isso funciona porque o tax_query cria as junções etc para você, basta solicitar por um dos campos da junção.

Francis Yaconiello
fonte
2
Alguma idéia de como solicitar pelo nome, em vez de term_taxonomy_id? Como alterar term_taxonomy_id em orderby_statement gera erros
tehlivi 4/16
Esta é a resposta correta para qualquer pessoa interessada!
Mayra M
2

Bem, gostaria de expor minha experiência na classificação de tipos de postagem personalizados por categoria / taxonomia.

A TEIA

  1. Um site de agência de viagens executando no WordPress
  2. Conteúdo principal no tipo de postagem personalizado chamado 'ruta'
  3. Taxonomia com essa estrutura Tipo de viagem> continente> país

O CASO

Nas páginas da lista de categorias de arquivo, o cliente queria que as postagens fossem classificadas por

  1. O continente, ordenado pelo número de rotas em cada uma.
  2. O país, ordenado alfabeticamente.

OS PASSOS

Primeiro , eu pego a solicitação da consulta da página de arquivamento não modificada, que era assim:

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 , editei o código sql no Sequel Pro no banco de dados para atender às minhas necessidades. Eu venho com isso (sim, provavelmente pode ser melhorado: meu conhecimento sobre MySQL não é 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  

Terceiro , vinculei a consulta no arquivo functions.php com três filtros: posts_fields, posts_join e posts_orderby

O código em 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, ativei os filtros do gancho pre_get_post de acordo com algumas condições

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 isso possa ajudar alguém

Xavier Caliz
fonte
Bom trabalho, ridículo que é preciso essa quantidade de código para classificar algo por uma taxonomia. Enorme problema com o WP.
serraosays
2

Eu tive um problema muito semelhante ao que lidei: quero solicitar um arquivo pós-tipo personalizado (artigos de revista) por uma taxonomia personalizada (questões). Eu nunca faço consultas SQL diretas no meu site - e geralmente se você gosta dessas outras respostas - precisa repensar sua abordagem.

PROBLEMAS:

1) O Wordpress não permite que você encomende taxonomias de forma inteligente.

2) O Wordpress simplesmente não permite o orderbyuso de taxonomias no WP_Query pós-tipo (como explicado por Otto).

SOLUÇÕES:

1) A classificação das taxonomias é melhor realizada no momento pelo plug-in Custom Taxonomy Order NE . Ele permite que você solicite a taxonomia via WYSIWYG na wp-adminqual não é como eu faria isso, mas não encontrei nada melhor.

Quando você configura o plug-in, obtém algo semelhante ao que eu fiz aqui. Anote a opção Auto-sort Queries of this Taxonomy- defina-a como Custom Order as Defined Above; isso faz com que você solicite o que precisa. Captura de tela:

Exibição de ordem de taxonomia personalizada NE

2) Com uma taxonomia classificada, agora você pode criar uma série de chamadas WP_Query que são executadas em cada termo, criando efetivamente um arquivo ordenado pela taxonomia. Use get_terms()para criar uma matriz de todos os termos fiscais e, em seguida, execute um foreachsobre cada termo. Isso cria um WP_Queryitem para cada termo que retornará todas as postagens para um determinado termo, criando efetivamente um arquivo ordenado por termo de taxonomia. Código para fazer isso acontecer:

  // 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;
  }

Leitura relacionada neste site: Exiba todas as postagens em um tipo de postagem personalizada, agrupadas por uma taxonomia personalizada

serraosays
fonte
2

Não sei por que todas as soluções aqui estão exagerando. OK, faz meia década, mas atualmente estou executando o seguinte código e 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);
    ?>

Isso classificará as taxonomias do seu CPT primeiro por sua taxonomia em ordem alfabética e dentro desses grupos de taxonomia também por ordem alfabética.

user3135691
fonte
@yeope Por que essa é a resposta aceita? graças a Deus eu rolei
Juan Solano
1

Aqui está a solução que eu usei para esse problema específico. Essa solução é para casos extremos em que não é possível usar um pre_get_postsfiltro e existe paginação existente na consulta (ou seja: 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);

Usei isso para criar um menu de navegação ordenado por taxonomia, termo e contagem de postagens por termo.

Se você deseja apenas as postagens, altere a consulta para SELECT p.*eGROUP BY p.ID

CodeShaman
fonte
0

É como uma consulta antes da consulta, mas não incomodará se não estivermos consultando muitas postagens ... A idéia é modificar a consulta principal para que nem precisemos ir aos modelos e gerar novas consultas e rotações...

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
fonte