it-swarm-eu.dev

Použití WP_Query k dotazování více kategorií s omezenými příspěvky na kategorii?

Mám 3 kategorie s každých 15 příspěvků, chci udělat ONE dotaz na db, který přináší pouze 5 prvních příspěvků pro každou kategorii, jak to mohu udělat?

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

V případě, že to není možné, co je efektivnější, získávání všech příspěvků pro nadřazenou kategorii a jejich opakování nebo vytváření 3 různých dotazů?

10
Amit

To, co chcete, je možné, ale bude vyžadovat, abyste se ponořili do SQL, kterému se chci vyhnout, kdykoli je to možné (ne proto, že to nevím, jsem vývojář SQL, ale protože in WordPress chcete použít API kdykoli je to možné minimalizovat budoucí problémy s kompatibilitou související s budoucími potenciálními změnami struktury databáze.)

SQL s operátorem UNION je možnost

Chcete-li použít SQL, co potřebujete, je operátor UNION ve vašem dotazu, něco takového za předpokladu, že vaše kategorie slugs jsou "category-1", "category-1" a "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
)

SQL UNION můžete použít s posts_join filtrem

Pomocí výše uvedeného můžete buď jen zavolat přímo nebo můžete použít posts_join háček filtru jako následovně; poznámka Používám PHP heredoc , takže se ujistěte, že SQL; je flush vlevo. Také jsem si všiml, že jsem použil globální var, abych vám umožnil definovat kategorie mimo háček výčtem kategorie slimáků v poli. Tento kód můžete umístit do pluginu nebo do souboru functions.php motivu:

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

Ale mohou být vedlejší účinky

Samozřejmě s použitím háčků pro modifikaci dotazů, jako je posts_join, vždy zvou vedlejší efekty v tom, že působí globálně na dotazy, a proto je obvykle nutné zabalit vaše změny do if, které je používají pouze v případě potřeby a jaká kritéria pro testování mohou být složitá.

Zaměřte se spíše na optimalizaci?

Domnívám se však, že vaše otázka se týká více o optimalizaci než o tom, že dokážete udělat 5 nejlepších dotazů v čase 3, ne? Pokud tomu tak je, pak možná existují další možnosti, které používají WordPress API?

Lepší je použití přechodových API pro ukládání do mezipaměti?

Předpokládám, že vaše příspěvky se nezmění tak často, správně? Co když přijmete periodicky tří (3) dotaz a poté výsledky uložíte pomocí Transients API ? Získáte udržovatelný kód a skvělý výkon; dobrý bit lepší než UNION dotaz výše, protože WordPress uloží seznamy příspěvků jako serializované pole v jednom záznamu tabulky wp_options.

Chcete-li si to vyzkoušet, můžete provést následující příklad a vložit jej do kořenového adresáře webu jako test.php:

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

Souhrn

Zatímco ano, můžete udělat to, co jste požadovali pro použití dotazu SQL UNION a háčku posts_join, což je pravděpodobně lepší nabídka pomocí mezipaměti sTransients API.

Snad to pomůže?

15
MikeSchinkel

WP_Query() nepodporuje něco jako First X For Each Cat . Namísto WP_Query() můžete použít get_posts() na každé z vašich kategorií, abych řekl třikrát:

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

$posts nyní obsahuje prvních pět příspěvků pro každou kategorii.

1
hakre

Nevím o způsobu, jak získat prvních pět příspěvků pro každou z kategorií v jediném dotazu. Pokud jste někdy bude mít pouze 45 míst, pak bít do databáze jednou a dostat své pět míst pro každou kategorii je pravděpodobně nejúčinnější přístup. Bít do databáze třikrát a kombinovat výsledky není špatná věc ačkoli.

0
Bernard Chen