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?
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.)
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
)
posts_join
En utilisant ce qui précède, vous pouvez soit vous appelez directement ou vous pouvez utilisez un crochet de filtre posts_join
comme 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 " ;
}
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.
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?
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);
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?
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.
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.