it-swarm.com.de

Verwenden Sie WP_Query, um mehrere Kategorien mit begrenzten Beiträgen pro Kategorie abzufragen?

Ich habe 3 Kategorien mit jeweils 15 Beiträgen. Ich möchte EINE Abfrage an die Datenbank senden, die nur 5 erste Beiträge für jede Kategorie enthält. Wie kann ich das tun?

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

Was ist effizienter, wenn es nicht möglich ist, alle Beiträge für die übergeordnete Kategorie abzurufen und in einer Schleife durchzugehen oder drei verschiedene Abfragen zu erstellen?

10
Amit

Was Sie wollen, ist möglich, erfordert aber, dass Sie sich mit SQL befassen, das ich nach Möglichkeit meide (nicht, weil ich es nicht kenne, ich bin ein fortgeschrittener SQL-Entwickler, sondern weil in WordPress Sie möchten die API wann immer möglich verwenden um zukünftige Kompatibilitätsprobleme im Zusammenhang mit zukünftigen möglichen Änderungen der Datenbankstruktur zu minimieren.)

SQL mit einem UNION Operator ist eine Möglichkeit

Wenn Sie SQL verwenden möchten, benötigen Sie einen Operator UNION in Ihrer Abfrage, vorausgesetzt, Ihre Kategorie-Slugs lauten "category-1", "category-1" und "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
)

Sie können SQL UNION mit einem posts_join-Filter verwenden

Mit dem obigen Befehl können Sie entweder den Anruf direkt tätigen oder einen posts_join-Filter-Hook verwenden wie folgt; note Ich verwende ein PHP heredoc also stelle sicher, dass der SQL; linksbündig ist. Beachten Sie auch, dass ich eine globale Variable verwendet habe, mit der Sie die Kategorien außerhalb des Hooks definieren können, indem Sie die Category-Slugs in einem Array auflisten. Sie können diesen Code in ein Plugin oder in die functions.php-Datei Ihres Themas einfügen:

<?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 " ;
}

Aber es kann Nebenwirkungen geben

Natürlich führt die Verwendung von Modifikations-Hooks für Abfragen wie posts_join immer zu Nebenwirkungen, da sie global auf Abfragen wirken. Daher müssen Sie Ihre Modifikationen normalerweise in eine if einbetten, die sie nur bei Bedarf verwendet, und es kann schwierig sein, auf welche Kriterien zu testen ist.

Konzentrieren Sie sich stattdessen auf die Optimierung?

Ich gehe jedoch davon aus, dass Ihre Frage mehr über die Optimierung ist, als über die Möglichkeit, eine Top-5-Abfrage für die Zeit 3 ​​durchzuführen, oder? Wenn dies der Fall ist, gibt es dann möglicherweise andere Optionen, die die WordPress-API verwenden?

Besser Transients API für das Caching verwenden?

Ich gehe davon aus, dass sich deine Posts nicht so oft ändern, richtig? Was ist, wenn Sie die drei (3) Abfragetreffer regelmäßig akzeptieren und die Ergebnisse dann mit der Transients-API zwischenspeichern? Sie erhalten wartbaren Code und eine hervorragende Leistung. Ein gutes Stückchen besser als die obige Abfrage UNION, da WordPress die Listen der Beiträge als serialisiertes Array in einem Datensatz der Tabelle wp_options speichert.

Sie können das folgende Beispiel nehmen und als test.php in das Stammverzeichnis Ihrer Website ablegen, um dies zu testen:

<?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);

Zusammenfassung

Ja, Sie können das, wonach Sie gefragt haben, mit einer SQL-Abfrage UNION und dem Filter-Hook posts_join tun. Wahrscheinlich ist es besser, Caching mit der OptionTransients APIzu verwenden.

Hoffe das hilft?

15
MikeSchinkel

WP_Query() unterstützt nicht so etwas wie First X For Each Cat . Anstelle von WP_Query() können Sie get_posts() für jede Ihrer Kategorien verwenden, also dreimal:

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

$posts enthält jetzt die ersten fünf Beiträge für jede Kategorie.

1
hakre

Ich kenne keine Möglichkeit, die ersten fünf Posts für jede der Kategorien in einer einzelnen Abfrage abzurufen. Wenn Sie jemals nur 45 Posts haben werden, ist es wahrscheinlich der effizienteste Ansatz, die Datenbank einmal zu besuchen und Ihre fünf Posts für jede Kategorie zu erhalten. Es ist jedoch nicht schlecht, dreimal auf die Datenbank zuzugreifen und die Ergebnisse zu kombinieren.

0
Bernard Chen