Usando wp_query é possível ordenar por taxonomia?

44

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

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

A ordenação em WP_Query permite que você ordene por um grupo de campos até mesmo campos meta personalizados, mas não parece apoiar a taxonomia.

Qualquer ponteiro na direção certa?

Obrigado a todos.

    
por yeope 08.04.2011 / 17:44
fonte

9 respostas

13

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

Taxonomias são maneiras de agrupar as coisas. Então, o objetivo de ter uma taxonomia em posts seria realmente ter termos nessa taxonomia que são compartilhados entre as postagens. Se uma taxonomia tivesse termos que só fossem usados em um post cada, isso tornaria a taxonomia meio sem sentido. E se os termos fossem compartilhados como deveriam, a encomenda não produziria nada particularmente útil.

O que você deve usar em tal situação é o post meta. Você pode encomendar por post meta, e é único para cada post.

Edit: Dito isto, você pode ordenar por taxonomia fazendo uma consulta SQL personalizada usando um filtro, você não pode fazer isso de uma WP_Query não modificada: enlace

No entanto, se você tiver que recorrer a esse tipo de coisa, a 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 grupo específico que estão descrevendo. Se você está tratando-os como dados significativos, então 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ê tem metadados significativos para atribuir a um post, então você deve usar o post meta para ele. E que você pode ordenar, porque post meta usa chaves e valores para armazenar informações. Com uma taxonomia, você está realmente apenas armazenando chaves, com seus valores sendo as postagens agrupadas por esse termo.

As coisas são mais fáceis a longo prazo se você usar a abordagem correta para isso. Embora eu não esteja dizendo que você não pode fazer algo estranho com a taxonomia, você está apenas tornando as coisas mais difíceis para você a longo prazo, usando-a de maneira errada.

    
por Otto 08.04.2011 / 18:20
fonte
36

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 de 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, terá agora um conjunto de resultados com todos os termos, mas eles são ordenados por data de postagem.

Para obter a ordem correta, em relação aos seus termos e, em seguida, para exibir no front end apropriadamente, separando as postagens em suas várias categorias, você tem que percorrer o conjunto de resultados e, em seguida, consultar cada indivíduo poste no conjunto de resultados para encontrar os termos e comparar com o termo atual, filtrar em uma matriz e continuar por toda parte. Então você tem que novamente percorrer o novo array para exibição. Isso não é produtivo.

Seria bom se WP tivesse uma opção "order" por exemplo, como faz uma "post__in", mas como isso não acontece, você tem que fazer o processo acima ridículo; personalizar a consulta por meio do filtro 'posts_orderby' e do filtro 'posts_join' para ajustar o método orderby e adicionar o termo ao conjunto de resultados, respectivamente; ou você precisa 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 com 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 precisarão fazer o pedido pelas mesmas condições.

    
por Aryan Duntley 28.07.2014 / 13:36
fonte
13

Sim, mas está 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 é frankensteined de algumas coisas encontradas e algumas coisas que eu fiz sozinho. Explicar é bem difícil, mas o resultado final é que, com isso, você pode colocar? Orderby = (taxonomy query var) e a ordem = ASC (ou DESC) e ela vai tirar logo!

    
por Drew Gourley 08.04.2011 / 18:36
fonte
8

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

Construa sua consulta fiscal como normal.

$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 consulta 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 se esqueça de remover o filtro depois ...

isso funciona b / c o tax_query cria as junções etc para você, você só precisa ordenar por um dos campos da junção.

    
por Francis Yaconiello 31.10.2014 / 14:48
fonte
2

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

A WEB

  1. Um site da agência de viagens em execução no WordPress
  2. Conteúdo principal no tipo de postagem personalizada chamado "ruta"
  3. Taxonomia com essa estrutura Tipo de viagem > continente > país

O CASO

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

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

OS PASSOS

Primeiro , vejo a solicitação da consulta de página de arquivo não modificada que aconteceu 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 saio com isso (sim, provavelmente pode ser melhorado: meu conhecimento sobre o MySQL não está pendente):

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 , conectei 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 eu acionei 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

    
por Xavier Caliz 04.01.2015 / 16:09
fonte
2

Eu tive um problema muito semelhante com o qual lidei: Quero solicitar um arquivo de pós-tipo personalizado (artigos de revista) por uma taxonomia personalizada (problemas). Eu nunca faço consultas diretas ao SQL em meu site - e normalmente, se você é como essas outras respostas - você precisa repensar sua abordagem.

PROBLEMAS:

1) O Wordpress não permite que você solicite taxonomias de maneira inteligente.

2) O Wordpress simplesmente não permite que orderby usem taxonomias em post-type WP_Query (como descrito por Otto).

SOLUÇÕES:

1) A classificação das taxonomias é melhor realizada pelo Plugin de ordem de taxonomia personalizada NE no momento. Ele permite que você solicite a taxonomia via WYSIWYG em wp-admin , que não é como eu faria, mas não encontrei nada melhor.

Quando você configurar o plugin, você terá algo parecido com o que eu fiz aqui. Anote a opção Auto-sort Queries of this Taxonomy - configure isso para Custom Order as Defined Above ; isso te dá a ordem que você precisa. Captura de tela:

2)Comumataxonomiaclassificadaemvigor,vocêpodecriarumasériedechamadasWP_Queryquesãoexecutadasemcadatermo,criandoefetivamenteumarquivoordenadopelataxonomia.Useget_terms()paracriarumamatrizdetodosostermosfiscaise,emseguida,executeumforeachsobrecadatermo.IssocriaumWP_Queryparacadaitemdetermoqueretornarátodasaspostagensdeumdeterminadotermo,criandoefetivamenteumarquivoordenadoportermodetaxonomia.Códigoparaqueissoaconteça:

//Getyourtermsandputthemintoanarray$issue_terms=get_terms(['taxonomy'=>'issues','hide_empty'=>false,]);//Runforeachovereachtermtosetupqueryanddisplayforpostsforeach($issue_termsas$issue_term){$the_query=newWP_Query(array('post_type'=>'post','tax_query'=>array(array('taxonomy'=>'issues','field'=>'slug','terms'=>array($issue_term->slug),'operator'=>'IN'))));//Runloopovereachquerywhile($the_query->have_posts()):$the_query->the_post();//YOURTEMPLATEOUTPUTFOREACHPOSTendwhile;}

Leiturarelacionadanestesite: Exibir todas as mensagens em um tipo de postagem personalizado, agrupado por uma taxonomia personalizada

    
por staypuftman 10.04.2017 / 16:45
fonte
1

Aqui está a solução que usei para esse problema específico. Esta solução é para casos extremos em que não é possível usar um filtro pre_get_posts e existe paginação na consulta (por exemplo: 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ê quiser apenas as postagens, altere a consulta para SELECT p.* e GROUP BY p.ID

    
por CodeShaman 24.03.2017 / 17:48
fonte
1

Não sei por que todas as soluções aqui são muito exageradas. OK, faz meia década, mas atualmente estou executando o código a seguir 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 por ordem alfabética.

    
por user3135691 06.07.2017 / 14:26
fonte
0

É como uma consulta antes da consulta, mas não se incomodará se não estivermos consultando muitas postagens ... A ideia é modificar a consulta principal para que não precisemos nem de ir a modelos e gerar novas consultas e loops ...

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' );
    
por Marcelo Viana 22.04.2017 / 08:38
fonte