Utilisation de WP_Query pour interroger plusieurs catégories avec des messages limités par catégorie?

10

J'ai 3 catégories avec chacune 15 publications, je veux faire UNE requête à la base de données n'apportant que 5 premières publications pour chaque catégorie, comment puis-je le faire?

$q = new WP_Query(array( 'post__in' => array(2,4,8), 'posts_per_page' => **FIRST_5_OF_EACH_CAT** ));

Si ce n’est pas possible, quoi de plus efficace, obtenir toutes les publications de la catégorie parent et les parcourir en boucle ou créer 3 requêtes différentes?

    
posée Amit 25.08.2010 - 22:28

3 réponses

15

Ce que vous voulez est possible, mais vous obliger à approfondir votre recherche sur SQL que j'aime éviter autant que possible (non pas parce que je ne le connais pas, je suis un développeur SQL avancé, mais parce que dans WordPress, vous souhaitez utiliser l'API chaque fois que cela est possible pour minimiser les futurs problèmes de compatibilité liés à de futures modifications de la structure de la base de données.)

SQL avec un opérateur UNION est une possibilité

Pour utiliser SQL, vous avez besoin d’un opérateur UNION dans votre requête. Par exemple, supposez que vos slugs de catégorie sont "category-1" , "category-1" et "category-3" :

SELECT * FROM wp_posts WHERE ID IN (
  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-1'
  LIMIT 5

  UNION

  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-2'
  LIMIT 5

  UNION

  SELECT tr.object_id
  FROM wp_terms t 
  INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
  INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
  WHERE tt.taxonomy='category' AND t.slug='category-3'
  LIMIT 5
)

Vous pouvez utiliser SQL UNION avec un filtre posts_join

En utilisant ce qui précède, vous pouvez passer directement l'appel ou utiliser un crochet de filtrage posts_join comme suit; note J'utilise un Heredoc PHP , alors assurez-vous que le SQL; est aligné à gauche. Notez également que j'ai utilisé une variable globale pour vous permettre de définir les catégories en dehors du crochet en listant les slugs de catégories dans un tableau. Vous pouvez mettre ce code dans un plugin ou dans le fichier functions.php de votre thème:

<?php
global $top_5_for_each_category_join;
$top_5_for_each_category_join = array('category-1','category-2','category-3');
add_filter('posts_join','top_5_for_each_category_join',10,2);
function top_5_for_each_category_join($join,$query) {
  global $top_5_for_each_category_join;
  $unioned_selects = array();
  foreach($top_5_for_each_category_join as $category) {
    $unioned_selects[] =<<<SQL
SELECT object_id
FROM wp_terms t
INNER JOIN wp_term_taxonomy tt ON t.term_id = tt.term_id
INNER JOIN wp_term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
WHERE tt.taxonomy='category' AND t.slug='{$category}'
LIMIT 5
SQL;
  }
  $unioned_selects = implode("\n\nUNION\n\n",$unioned_selects);
  return $join . " INNER JOIN ($unioned_selects) categories ON wp_posts.ID=categories.object_id " ;
}

Mais il peut y avoir des effets secondaires

Bien sûr, en utilisant les crochets de modification de requête tels que posts_join , vous obtenez toujours des effets secondaires dans la mesure où ils agissent globalement sur les requêtes. Par conséquent, vous devez généralement envelopper vos modifications dans un if qui ne l'utilise que lorsque vous en avez besoin et selon quels critères. test peut être délicat.

Concentrez-vous sur l'optimisation?

Toutefois, je suppose que votre question concerne plus l'optimisation que la possibilité d'effectuer une requête parmi les cinq meilleures fois, n'est-ce pas? Si tel est le cas, il existe peut-être d’autres options utilisant l’API WordPress?

Il est préférable d’utiliser l’API transitoires pour la mise en cache?

Je suppose que vos publications ne changeront pas souvent, n'est-ce pas? Que se passe-t-il si vous acceptez les trois (3) requêtes consultées périodiquement, puis mettez les résultats en cache à l'aide de API Transients ? Vous obtiendrez un code maintenable et d'excellentes performances. un peu mieux que la requête UNION ci-dessus, car WordPress stockera les listes d'articles en tant que tableau sérialisé dans un enregistrement de la table wp_options .

Vous pouvez prendre l'exemple suivant et vous rendre à la racine de votre site Web sous test.php pour le tester:

<?php

$timeout = 4; // 4 hours
$categories = array('category-1','category-2','category-3');

include "wp-load.php";
$category_posts = get_transient('top5_posts_per_category');
if (!is_array($category_posts) || count($category_posts)==0) {
  echo "Hello Every {$timeout} hours!";
  $category_posts = array();
  foreach($categories as $category) {
    $posts = get_posts("post_type=post&numberposts=5&taxonomy=category&term={$category}");
    foreach($posts as $post) {
      $category_posts[$post->ID] = $post;
    }
  }
  set_transient('top5_posts_per_category',$category_posts,60*60*$timeout);
}
header('Content-Type:text/plain');
print_r($category_posts);

Résumé

Bien que vous puissiez faire ce que vous avez demandé en utilisant une requête SQL UNION et le crochet de filtrage posts_join , vous êtes probablement mieux placé en utilisant la mise en cache avec l'API Transients . > à la place.

Espérons-nous que cela vous aide?

    
réponse donnée MikeSchinkel 26.08.2010 - 00:23
1

WP_Query() ne prend pas en charge quelque chose comme Premier X pour chaque chat . Au lieu de WP_Query() , vous pouvez utiliser get_posts() sur chacune de vos catégories, pour ainsi dire trois fois:

<?php
$posts      = array():
$categories = array(2,4,8);
foreach($categories as $cat) {
  $posts[] = get_posts('numberposts=5&offset=1&category='.$cat);
}
?>

$posts contient maintenant les cinq premiers articles de chaque catégorie.

    
réponse donnée hakre 25.08.2010 - 22:54
0

Je ne connais pas de moyen d'obtenir les cinq premiers articles pour chacune des catégories d'une requête. Si vous n'allez avoir que 45 publications, alors sélectionner la base de données et obtenir vos cinq publications pour chaque catégorie est probablement l'approche la plus efficace. Frapper la base de données trois fois et combiner les résultats n’est pas une mauvaise chose cependant.

    
réponse donnée Bernard Chen 25.08.2010 - 22:38

Lire d'autres questions sur les étiquettes