Utiliser wp_query est-il possible de commander par taxonomie?

44

Ma question est simple. J'utilise WP_Query pour récupérer des publications de type personnalisé filtrées par une taxonomie à l'aide de tax_query.

Maintenant, le problème est que je voudrais commander par taxonomie, mais je ne trouve pas de solution à la documentation et aux recherches sur le Web.

Le paramètre orderby dans WP_Query vous permet de gérer plusieurs champs, même des méta-champs personnalisés, mais cela ne semble pas prendre en charge la taxonomie.

Des indications dans la bonne direction?

Merci à vous tous.

    
posée yeope 08.04.2011 - 17:44

9 réponses

13

Non, il n'est pas possible de classer par taxonomie car, d'un certain point de vue, cela n'a pas vraiment de sens.

Les taxonomies sont des moyens de regrouper des éléments. Donc, l’intérêt d’avoir une taxonomie sur les postes serait vraiment d’avoir des termes de cette taxonomie partagés entre les postes. Si une taxonomie comportait des termes qui n'étaient utilisés que sur un seul poste, cela rendrait la taxonomie inutile. Et si les termes étaient partagés comme ils devraient l'être, alors commander par celui-ci ne produirait rien de particulièrement utile.

Ce que vous devriez utiliser dans une telle situation est le post méta. Vous pouvez commander par la poste méta, et chaque commande est unique.

Édition: Cela dit, vous pouvez commander par taxonomie en faisant une requête SQL personnalisée à l'aide d'un filtre. Vous ne pouvez pas le faire depuis un WP_Query non modifié: enlace

Cependant, si vous devez recourir à ce type de processus, la structure de conception de vos données est incorrecte en premier lieu. Les "termes" dans la taxonomie ne sont pas des "données" réelles. Les termes eux-mêmes n'ont pas de signification inhérente, ils sont simplement des étiquettes pour le groupe particulier qu'ils décrivent. Si vous les traitez comme des données significatives, vous avez un défaut de conception sous-jacent.

Les taxonomies groupent les choses en leur assignant des termes. Ce groupement est l’essentiel des taxonomies, les termes sont simplement de jolis visages sur le groupement. Si vous devez affecter des métadonnées significatives à une publication, vous devriez plutôt utiliser la méta de publication correspondante. Et que vous pouvez commander, car meta utilise des clés et des valeurs pour stocker des informations. Avec une taxonomie, vous ne stockez que des clés, leurs valeurs étant les articles regroupés par ce terme.

À long terme, les choses sont plus faciles si vous utilisez la bonne approche. Bien que je ne dis pas que vous ne pouvez pas faire quelque chose d'étrange avec la taxonomie, vous ne faites que rendre les choses plus difficiles pour vous-même à long terme en les utilisant mal.

    
réponse donnée Otto 08.04.2011 - 18:20
36

La réponse acceptée pour cette question est inacceptable. Il est illogique de supposer qu'une commande par taxe "n'a pas de sens". La réponse qu'il a donnée n'a pas de sens.

Pensez à avoir un type de message de menu. Ensuite, vous avez une taxe personnalisée de "FoodCategories". La taxe FoodCategories comprend les termes "Petit déjeuner", "Déjeuner" et "Dîner". Si vous soumettez une requête en utilisant le paramètre tax_query, vous avez maintenant un ensemble de résultats avec tous les termes, mais ils sont classés par date de publication.

Pour obtenir le bon ordre, par rapport à leurs termes, puis pour les afficher au début de manière appropriée en séparant les publications dans leurs différentes catégories, vous devez parcourir le jeu de résultats, puis interroger chaque personne. poster dans le jeu de résultats pour trouver ses termes et les comparer au terme actuel, filtrer dans un tableau et continuer tout au long. Ensuite, vous devez à nouveau parcourir le nouveau tableau pour l'affichage. Ce n'est pas productif.

Il serait bien que WP dispose d’une option "tax__in", comme une option "post__in", mais comme ce n’est pas le cas, vous devez également suivre le processus ridicule ci-dessus. personnalisez vous-même la requête à l'aide des filtres 'posts_orderby' et 'posts_join' afin d'ajuster la méthode orderby et d'ajouter le terme au jeu de résultats, respectivement; ou vous devez créer une nouvelle requête pour chaque terme que vous filtrez dans les sections html relatives à ces termes.

Le plus efficace serait de changer la chaîne de requête au moyen de filtres. Le plus simple serait de faire trois requêtes distinctes. L'API WP devrait gérer les commandes par taxe ou tout paramètre de requête restrictif. Si vous limitez une requête en fonction de certaines conditions, il est fort probable que beaucoup auront besoin de passer commande selon ces mêmes conditions.

    
réponse donnée Aryan Duntley 28.07.2014 - 13:36
13

Oui, mais c'est assez compliqué ...

Ajouter au fichier functions.php dans votre thème:

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

C’est frankensteined à partir de choses trouvées et de choses que j’ai faites moi-même. Expliquer est assez difficile, mais le résultat final est que vous pouvez exécuter? Orderby = (requête de taxonomie var) et order = ASC (ou DESC) et elle se retirera immédiatement!

    
réponse donnée Drew Gourley 08.04.2011 - 18:36
8

Je viens en retard au jeu ici, mais il existe un moyen plus simple et plus WordPressy de le faire.

Construisez votre requête fiscale comme d'habitude.

$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;

Configurez vos arguments pour query_posts ou WP_Query

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

Avant de passer votre appel à query_posts / WP_Query, connectez-vous au filtre orderby et remplacez-le

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'oubliez pas de supprimer le filtre par la suite ...

cela fonctionne car tax_query crée les jointures, etc. pour vous, il vous suffit de commander par l'un des champs de la jointure.

    
réponse donnée Francis Yaconiello 31.10.2014 - 14:48
2

Eh bien, j'aimerais exposer mon expérience en matière de tri des types d'articles personnalisés par catégorie / taxonomie.

LE WEB

  1. Un site Web d'agence de voyages sous WordPress
  2. Contenu principal du type de message personnalisé appelé "ruta"
  3. Taxonomie avec cette structure Type de déplacement > continent > pays

LE CAS

Dans les pages de liste de catégories d'archives, le client souhaitait que les articles soient triés par

.
  1. Le continent, classé par nombre de routes sur chacune d'elles.
  2. Le pays, classé par ordre alphabétique.

LES ÉTAPES

Tout d'abord , je récupère la requête de la requête de page d'archive non modifiée qui se présentait de la manière suivante:

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

Deuxièmement , j'ai modifié le code SQL de Sequel Pro par rapport à la base de données pour répondre à mes besoins. Je sors avec cela (oui, cela peut probablement être amélioré: mon connaissances sur MySQL n’est pas remarquable):

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  

Troisième , j'ai lié la requête au fichier functions.php avec trois filtres: posts_fields, posts_join et posts_orderby

Le code dans 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;
 }

Enfin , j'ai déclenché les filtres à partir du hook pre_get_post en fonction de certaines conditions

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

J'espère que cela peut aider quelqu'un

    
réponse donnée Xavier Caliz 04.01.2015 - 16:09
2

J'ai eu un problème très similaire que j'ai résolu: je veux commander une archive de type post personnalisée (articles de magazines) par une taxonomie personnalisée (questions). Je ne fais jamais de requêtes SQL directes sur mon site - et généralement si vous êtes comme ces autres réponses - vous devez repenser votre approche.

PROBLÈMES:

1) Wordpress ne vous permet pas de commander des taxonomies de manière intelligente.

2) Wordpress n'autorise pas orderby à utiliser des taxonomies sur les post-types WP_Query (comme indiqué par Otto).

SOLUTIONS:

1) Le meilleur moyen de trier les taxonomies est le Custom Taxonomy Order NE plug-in pour le moment. Cela vous permet de commander la taxonomie via WYSIWYG dans wp-admin , ce qui n’est pas comme je le ferais mais je n’ai rien trouvé de mieux.

Lorsque vous installez le plug-in, vous obtiendrez quelque chose de similaire à ce que j'ai fait ici. Notez l’option Auto-sort Queries of this Taxonomy - définissez cette option sur Custom Order as Defined Above ; cela vous donne la commande dont vous avez besoin. Capture d'écran:

2)Avecunetaxonomietriéeenplace,vouspouvezdésormaiscréeruneséried'appelsWP_Queryquiparcourentchaqueterme,créantainsiunearchiveordonnéeparlataxonomie.Utilisezget_terms()pourcréeruntableaudetouslestermesdetaxe,puisexécutezunforeachsurchaqueterme.CelacréeunWP_Querypourchaqueélémentdetermequirenverratouteslespublicationspouruntermedonné,créantainsiunearchiveclasséepartermedetaxonomie.Codepourquecelaseproduise:

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

Lectureconnexesurcesite: Afficher tous les articles de un type d'article personnalisé, groupé par une taxonomie personnalisée

    
réponse donnée staypuftman 10.04.2017 - 16:45
1

Voici la solution que j'ai utilisée pour résoudre ce problème particulier. Cette solution est destinée aux cas extrêmes où il est impossible d'utiliser un filtre pre_get_posts et qu'il existe une pagination existante sur la requête (par exemple, 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);

Je l'ai utilisé pour créer un menu de navigation classé par taxonomie, terme et nombre de posts par terme.

Si vous voulez simplement les publications, changez la requête en SELECT p.* et GROUP BY p.ID

    
réponse donnée CodeShaman 24.03.2017 - 17:48
1

Je ne suis pas sûr de savoir pourquoi toutes les solutions proposées ici surpassent les attentes. OK, il y a une demi-décennie, mais je ne fais que lancer le code suivant actuellement et cela fonctionne:

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

Ceci va trier les taxonomies de votre CPT en fonction de sa taxonomie par ordre alphabétique et au sein de ces groupes de taxonomie ainsi que par ordre alphabétique.

    
réponse donnée user3135691 06.07.2017 - 14:26
0

C'est comme une requête avant la requête, mais cela ne dérange pas si nous n'interrogeons pas trop de messages ... L'idée est de modifier la requête principale pour ne pas avoir besoin d'aller aux modèles et de générer nouvelles requêtes et boucles ...

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' );
    
réponse donnée Marcelo Viana 22.04.2017 - 08:38

Lire d'autres questions sur les étiquettes