web-dev-qa-db-fra.com

Utilisation de WP_Query pour interroger plusieurs catégories avec un nombre limité de publications par catégorie?

J'ai 3 catégories avec chacune 15 publications, je veux faire UNE requête à la base de données apportant seulement 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** ));

Au cas où ce ne serait pas possible, quoi de plus efficace: récupérer toutes les publications de la catégorie parente et les parcourir en boucle ou créer 3 requêtes différentes?

10
Amit

Ce que vous voulez est possible mais vous demandera de plonger dans SQL que je préfère éviter autant que possible (non pas parce que je ne le sais pas, je suis un développeur SQL avancé, mais parce que in WordPress vous souhaitez utiliser l'API chaque fois que possible pour minimiser les futurs problèmes de compatibilité liés aux futures modifications éventuelles de la structure de la base de données.)

SQL avec un opérateur UNION est une possibilité

Pour utiliser SQL, ce dont vous avez besoin est un opérateur UNION dans votre requête, en supposant que vos slug de catégorie soient "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 soit vous appelez directement ou vous pouvez utilisez un crochet de filtre posts_joincomme ci-dessous; note J'utilise un PHP heredoc , alors assurez-vous que le SQL; est vide. 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, l'utilisation de crochets de modification de requête tels que posts_join entraîne toujours des effets secondaires, en ce sens qu'ils agissent globalement sur les requêtes. Vous devez donc généralement envelopper vos modifications dans une if qui ne l'utilise que lorsque cela est nécessaire et quels critères tester peuvent être difficiles.

Se concentrer sur l'optimisation à la place?

Cependant, je suppose que votre question concerne plus sur l'optimisation que sur la possibilité de faire une requête dans le top 5 du temps 3, n'est-ce pas? Si tel est le cas, il existe peut-être d'autres options qui utilisent l'API WordPress?

Mieux vaut utiliser l'API transitoires pour la mise en cache?

Je suppose que vos messages ne changeront pas souvent, n'est-ce pas? Que se passe-t-il si vous acceptez périodiquement les trois (3) requêtes et que vous mettez ensuite les résultats en cache à l’aide de l’API Transitoires ? 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 dans un tableau sérialisé dans un enregistrement de la table wp_options.

Vous pouvez prendre l'exemple suivant et déposer le code test.php à la racine de votre site Web pour le vérifier:

<?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 filtre posts_join, vous êtes probablement mieux placé en utilisant la mise en cache avecAPI de transitoireà la place.

J'espère que cela t'aides?

15
MikeSchinkel

WP_Query() ne supporte pas 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.

1
hakre

Je ne connais pas de moyen d'obtenir les cinq premiers articles pour chacune des catégories en une seule requête. Si vous comptez ne publier que 45 publications, alors consulter la base de données une seule fois et obtenir vos cinq publications pour chaque catégorie est probablement la méthode la plus efficace. Frapper la base de données trois fois et combiner les résultats n'est pas une mauvaise chose cependant.

0
Bernard Chen