web-dev-qa-db-fra.com

WP Groupe de requêtes/ordre par nom de catégorie

J'ai l'obligation d'afficher une liste de types de messages personnalisés regroupés par catégorie, mais chaque message personnalisé est en outre lié à une méta-valeur (dans cet exemple, supposons que nous ayons une méta-valeur personnalisée de "TEST1").

Fondamentalement, mon objectif est d’afficher une liste, regroupée par catégorie pour toutes les publications personnalisées portant le code "TEST1". Je le fais actuellement en obtenant simplement toutes les catégories liées à mon type de publication personnalisé (en ignorant les vides), puis en parcourant chaque catégorie pour obtenir toutes les publications qui contiennent le code "TEST1".

Maintenant, c’est génial, cela fonctionne bien, mais c’est extrêmement inefficace. Pour le moment, ce n'est pas un problème, mais je crains que cela ne se répande pas très bien à mesure que le nombre de catégories augmente avec le temps, car chaque itération équivaut à un autre hit de base de données (et rejoint la table méta post).

J'ai jeté un coup d'œil sur le Web, mais je suis incapable de trouver quoi que ce soit, mais je me demandais s'il était possible d'effectuer un appel WP_Query qui renverrait toutes les publications avec la méta-valeur personnalisée de "TEST1" regroupées ou classées par nom de catégorie. Ce serait beaucoup plus efficace (en gros, 1 coup de DB, je suppose). Si quelqu'un peut conseiller quelque chose ici, je vous en serais très reconnaissant. S'il n'est pas possible, je suppose que mon seul moyen d'y parvenir serait de faire une requête directe à la base de données à partir de mon plugin (ce que j'ai lu n'est pas conseillé lorsque vous travaillez avec des plugins).

2
hdougie

Vous pouvez le faire de plusieurs manières.

Le plus simple est de tout obtenir: les posts et les termes, puis d'utiliser la magie array_filter pour grouper les choses. Exemple simple (qui ne fonctionnera qu'avec PHP 5.3+):

<?php
$terms = get_terms('your_taxonomy');

$term_ids = array_map(function($t) {
    return $t->term_id,
}, $terms);

$posts = get_posts(array(
    'nopaging'      => true,
    'tax_query'     => array(
        array(
            'taxonomy'  => 'category',
            'field'     => 'id',
            'terms'     => $term_ids,
        ),
    ),
    'meta_query'    => array(
        array(
            'key'       => 'TEST1',
            'compare'   => 'EXISTS', // wp 3.5+ only
        )
    ),
));

foreach ($terms as $t) {
    $posts_in_term = array_filter($posts, function($p) use ($t) {
        // has_term likely triggers a DB hit...
        return has_term($t->term_id, 'your_taxonomy', $p);
    });

    // do stuff with $posts_in_term 
}

C'est assez facile à comprendre. Vous prenez beaucoup de travail de commande que vous auriez envoyé à la base de données et l'avez fait dans l'application PHP elle-même. Pas mal, certainement moins de hits DB que vous faisiez. Si vous avez besoin de mettre un titre avec chaque nom de catégorie, ce serait probablement la voie à suivre car cela sera très difficile avec la méthode suivante.

Option 2: Effectuez la requête get_posts comme d'habitude, mais connectez-vous à posts_groupby et commandez par ID. Vous devez faire des recherches pour trouver les alias/noms de table à classer dans la classe WP_Tax_Query qui crée des alias de table en fonction du nombre de requêtes de taxonomie contenues dans un ensemble donné. Comme nous n'en avons qu'un, il n'y a pas d'allias et il vous suffit d'ajouter $wpdb->term_relationships.object_id au groupe par. Le résultat final est quelque chose qui ressemble à GROUP BY $wpdb->posts.ID, $wpdb->term_relationships.object_id.

Exemple:

<?php
// our group by callback
function wpse84243_groupby($groupby, $query) {
    global $wpdb;

    return $groupby . ' ' . $wpdb->term_relationships . '.object_id';
}

add_filter('posts_groupby', 'wpse84243_groupby', 10, 2);
$posts = get_posts(array(
    'nopaging'      => true,
    'tax_query'     => array(
        array(
            'taxonomy'  => 'category',
            'field'     => 'id',
            'terms'     => get_terms('category', array('fields' => 'ids')),
        ),
    ),
    'meta_query'    => array(
        array(
            'key'       => 'TEST1',
            'compare'   => 'EXISTS', // wp 3.5+ only
        )
    ),
));

// remove the filter, put things back to normal
remove_filter('posts_groupby', 'wpse84243_groupby', 10, 2);

// do stuff with $posts, they'll be grouped by your taxonomy ID.
1
chrisguitarguy