问题描述
我有 3 个类别,每 15 个帖子,我想做一个查询数据库,每个类别只有 5 个第一个帖子,我该怎么办?
$q = new WP_Query(array( 'post__in' => array(2,4,8), 'posts_per_page' => **FIRST_5_OF_EACH_CAT** ));
如果不可能,什么是更有效率,获取父类别的所有帖子并循环遍历或创建 3 个不同的查询?
最佳解决方案
你想要的是可能的,但是需要你深入研究我喜欢避免的 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;
是齐平的。另请注意,我使用全局变量,允许您通过列出数组中的类别 lug 子来定义钩子外的类别。您可以将此代码放入插件或主题的 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("nnUNIONnn",$unioned_selects);
return $join . " INNER JOIN ($unioned_selects) categories ON wp_posts.ID=categories.object_id " ;
}
但是可以是 Side-effects
当然,使用像 posts_join
这样的查询修改钩子总是邀请 side-effects,因为它们在查询上全局地执行操作,因此通常需要在 if
中进行修改,if
只在需要时使用它,并且要测试的标准可能很棘手。
专注于优化?
然而,我认为你的问题更关心优化是关于能够做一个前 5 名 3 查询,对吗?如果是这种情况,那么也许还有其他使用 WordPress API 的选项?
更好地使用瞬态 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
筛选器钩子来进行所需的操作,而不是使用 Transient API 进行缓存。
希望这可以帮助?
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。