web-dev-qa-db-fra.com

Avec wp_query, est-il possible de commander par taxonomie?

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

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

Avec orderby dans WP_Query, vous pouvez classer par champs, même des méta-champs personnalisés, mais cela ne semble pas prendre en charge la taxonomie.

Des pointeurs dans la bonne direction?

Merci à tous.

48
yeope

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 dans 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 c'est unique à chaque poste.

Edit: Cela dit, vous pouvez classer 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é: http://scribu.net/wordpress/sortable-taxonomy-columns. html

Cependant, si vous devez recourir à ce type de processus, la structure de conception de vos données est erronée. Les "termes" dans la taxonomie ne sont pas des "données" réelles. Les termes eux-mêmes n'ont aucune 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 regroupent les choses en leur attribuant 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 commandez par, car meta utilise à la fois des clés et des valeurs pour stocker des informations. Avec une taxonomie, vous ne stockez réellement que des clés, leurs valeurs étant les posts regroupés par ce terme.

Les choses sont plus faciles à long terme 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.

13
Otto

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.

Afin d’en obtenir le bon ordre, par rapport à leurs termes, puis d’être affichés au début du système en séparant les publications dans leurs différentes catégories, vous devez parcourir le jeu de résultats, puis interroger chaque publication dans la liste. 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.

Ce serait bien si WP avait l'option "tax__in" orderby comme c'est le cas "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 doit 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.

43
Aryan Duntley

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

Ajoutez à 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 de certains trucs trouvés et des trucs que j'ai faits moi-même. Expliquer est assez difficile, mais le résultat final est que vous pouvez exécuter? Orderby = (requête de taxonomie var) & order = ASC (ou DESC) et elle décollera immédiatement!

15
Drew Gourley

J'arrive 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 retirer le filtre par la suite ...

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

9
Francis Yaconiello

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

LA TOILE

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

L'AFFAIRE

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 chacun.
  2. Le pays, classé par ordre alphabétique.

LES MARCHES

Tout d'abord , je récupère la requête de la requête de la 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 dans Sequel Pro par rapport à la base de données pour répondre à mes besoins. Je viens avec cela (oui, probablement, cela peut être amélioré: mes connaissances sur MySQL ne sont pas exceptionnelles):

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èmement , j'ai accroché 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 selon 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

2
Xavier Caliz

J'ai eu un problème très similaire que j'ai traité: je veux commander une archive de type post personnalisé (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 ne permet tout simplement pas à orderby d’être une taxonomie utilisée sur le post-type WP_Query (comme l’a expliqué Otto).

SOLUTIONS:

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

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

 Custom Taxonomy Order NE display 

2) Avec une taxonomie triée en place, vous pouvez désormais créer une série d'appels WP_Query qui passent par chaque terme, créant ainsi une archive ordonnée par la taxonomie. Utilisez get_terms() pour créer un tableau de tous les termes de taxe, puis exécutez une foreach sur chaque terme. Cela crée un WP_Query pour chaque élément de terme qui renvoie tous les articles pour un terme donné, créant ainsi une archive classée par terme de taxonomie. Code pour y arriver:

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

Lecture connexe sur ce site: Afficher tous les articles dans un type d'article personnalisé, regroupés par une taxonomie personnalisée

2
staypuftman

Je ne suis pas sûr de savoir pourquoi toutes les solutions proposées ici surpassent assez. OK, il y a une demi-décennie, mais j'utilise actuellement le code suivant 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);
    ?>

Cela 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.

1
user3135691

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

J'ai utilisé cela pour créer un menu de navigation ordonné 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

1
CodeShaman

C'est comme une requête avant la requête, mais cela ne dérange pas si nous n'interrogeons pas trop de publications ... L'idée est de modifier la requête principale de manière à ce que nous n'ayons même pas besoin d'aller aux modèles et de générer de nouvelles requêtes. 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' );
0
Marcelo Viana