使用WP_Query查询多个类别且每个类别的帖子数量有限?


10

我每15个帖子有3个类别,我想对数据库进行一次查询,每个类别仅带5个第一篇帖子,我该怎么办?

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

如果不可能的话,哪种方法更有效,获取父类别的所有帖子并循环浏览它们,或者创建3个不同的查询?


您如何订购它们?
MikeSchinkel 2010年

最近公布的..所以最近A类5,最近的B类等的东西
阿米特

好的,请在下面查看我的答案
MikeSchinkel 2010年

Answers:


16

您想要的是可能的,但是需要您尽可能深入地研究我想避免使用的SQL(不是因为我不知道,我是高级SQL开发人员,而是因为在WordPress中,您希望尽可能使用API以最大程度地减少与将来潜在的数据库结构更改有关的未来兼容性问题。)

UNION运算符的SQL 是可能的

要使用SQL你需要的是一个UNION在查询操作,像这样假设你的类别蛞蝓"category-1""category-1"以及"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与posts_join过滤器一起使用

使用以上方法,您可以直接拨打电话,也可以使用posts_join如下所示过滤器挂钩;请注意,我使用的是PHP Heredoc,因此请确保已将SQL;刷新。还要注意,我使用了一个全局变量来允许您通过在数组中列出类别标签来定义钩子之外的类别。您可以将此代码放在插件或主题functions.php文件中:

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

但可能会有副作用

当然,使用查询修改挂钩posts_join总是会产生副作用,因为它们会对查询产生全局影响,因此,通常需要将修改包装在if,仅在需要时使用它,并且要测试的标准可能很棘手。

专注于优化吗?

但是,我认为您所关心的问题更多关于优化,而不是关于能够进行前5次3查询,对吗?如果是这样,那么也许还有其他使用WordPress API的选项?

更好地使用Transients API进行缓存?

我认为您的帖子不会经常更改,对吗?如果您定期接受三(3)个查询命中然后使用Transients API缓存结果怎么办?您将获得可维护的代码和出色的性能;比UNION上面的查询好一点,因为WordPress会将帖子列表作为序列化数组存储在表的一条记录中wp_options

您可以使用以下示例并进入您网站的根目录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);

摘要

是的,您可以使用SQL UNION查询和posts_join过滤器挂钩完成您所要求的操作,而最好使用Transients API进行缓存来提供。

希望这可以帮助?


2
通过瞬态进行缓存对于减少对站点的影响是一件好事。
hakre 2010年

1
@Mike使用瞬态的好主意。
Chris_O 2010年

@迈克,如果我住在你的大陆上,我会和你一起上课的!再次感谢!
阿米特(Amit)2010年

@Amit:哈哈!:-)
MikeSchinkel 2010年

1
您还可以无限期保存瞬态,然后在save_post上刷新它吗?抄本中有一个很好的例子(使用edit_term钩子)
helgatheviking 2012年

1

WP_Query()不支持First X For Each Cat之类的功能。而不是WP_Query()可以get_posts()在每个类别上使用,可以说三遍:

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

$posts 现在包含每个类别的前五个帖子。


那不是3次命中数据库吗?我想知道您是否可以一击即办,因为我认为这样更有效。
阿米特(Amit)2010年

那么这就是数据库的目的,对不对?从中查询数据。该数据库是为这种东西。它可能比运行您要的复杂SQL查询更快。不要害怕使用这些东西。如果它破坏了您的网站,请在此处报告。
hakre 2010年

mm ..知道了,我对php / mysql / db的效率了解不多(想了解更多),确定命中数越少越好,然后自己解析结果。
阿米特(Amit)2010年

1
好吧,是的,一般来说,越来越多,越来越少。但是先尝试进行测试。您的软件越“糟糕”,它具有更大的优化潜力。因此,您可以边做边学,因为最终您会更快地编写出更好的软件,并且更快地编写出更好的软件。
hakre 2010年

0

我不知道一种在单个查询中获取每个类别的前五个帖子的方法。如果您只有45个帖子,那么一次访问数据库并为每个类别获取5个帖子可能是最有效的方法。击中数据库三遍并合并结果并不是一件坏事。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.