需求:精选置顶 + 不重复
Bricks Facebook 群里有用户求助:他想在 Bricks 的查询结果里同时显示 5 个 CPT(资源类文章),要求:
-
查询结果前 2 条必须是不同 CPT 里最新的、被标记为 “Featured”(基于 ACF 的是/否字段)的 2 篇文章;
-
其余结果按日期顺序继续排列,不能重复这 2 篇精选文章;
-
精选文章永远至少 2 篇,但只有最新的 2 篇置顶,第 3、4、5 篇精选就按正常顺序出现在结果里;
-
结果要用 Bricks 的筛选功能,所以不能用两个查询循环拼。
这类“精选置顶”需求在内容站里很常见:编辑希望把重点内容顶到列表最前面,其余按时间自然排序。难点在于“置顶的同时不能重复出现”,用两个查询循环拼的话,精选文章会同时在两个循环里出现,而且 Bricks 的 Query Filters 筛选器只作用于单个循环,无法跨循环工作。
一个查询循环、一个 PHP 查询就能解决。
核心思路:取 ID 再合并
方案分三步:
-
取精选:查最新 2 篇
featured字段为 1 的文章,只要 ID。 -
取其余:查全部文章,用
post__not_in排除刚才那 2 篇精选,只要 ID。 -
合并:把精选 ID 数组放在前面、其余 ID 接在后面,用
post__in+orderby => post__in让 Bricks 严格按这个顺序输出。
为什么要“只要 ID”?因为两个查询的排序规则不同(精选按时间取前 2,其余按时间全量),直接在 SQL 层用一条查询做“先精选后其余”很麻烦,而分两次取 ID 再合并,逻辑清晰、容易维护,还能顺便去重。fields => 'ids' 让 get_posts() 只返回 ID 数组,内存占用极小。
完整 PHP 查询代码
在 Query Loop 的 PHP 查询编辑器(Query editor)里粘贴:
// 定义你的文章类型 - 按实际 CPT slug 调整
$post_types = ['resource']; // 或 ['type1', 'type2', 'type3', 'type4', 'type5']
// 第 1 步:取最新 2 篇精选文章
$featured_args = [
'post_type' => $post_types,
'posts_per_page' => 2,
'orderby' => 'date',
'order' => 'DESC',
'meta_query' => [
[
'key' => 'featured', // 换成你的 ACF 字段名
'value' => '1',
'compare' => '='
]
],
'fields' => 'ids',
'no_found_rows' => true,
];
$featured_post_ids = get_posts( $featured_args );
// 第 2 步:取其余文章(排除 2 篇精选)
$other_args = [
'post_type' => $post_types,
'posts_per_page' => 100, // 按预计文章总数调整
'orderby' => 'date',
'order' => 'DESC',
'fields' => 'ids',
'no_found_rows' => true,
];
// 找到精选就排除掉
if ( ! empty( $featured_post_ids ) ) {
$other_args['post__not_in'] = $featured_post_ids;
}
$other_post_ids = get_posts( $other_args );
// 第 3 步:合并数组 - 精选在前,其余在后
$final_post_ids = array_merge( $featured_post_ids, $other_post_ids );
// 没有文章时返回空结果
if ( empty( $final_post_ids ) ) {
return ['post__in' => [0]];
}
// 第 4 步:返回查询参数,保持顺序
return [
'post_type' => $post_types,
'posts_per_page' => -1, // 全部显示,或设数字用于分页
'post__in' => $final_post_ids,
'orderby' => 'post__in', // 保持我们设定的顺序
'no_found_rows' => true,
];
相关阅读:
使用说明与坑
-
把
$post_types数组换成你自己的 CPT slug;多 CPT 直接列在数组里。 -
把
'featured'换成你的 ACF 是/否字段名。ACF 是/否字段勾选后存储值为1。 -
posts_per_page => 100是“其余文章”的上限,按站点规模调大即可。 -
orderby => 'post__in'是整段代码的灵魂:WordPress 默认会按日期重排post__in的结果,必须显式声明保持数组顺序。 -
no_found_rows => true能省一次 COUNT 查询,循环不需要分页计数时记得带上。 -
空结果处理:
['post__in' => [0]]是 WordPress 里“返回空”的惯用写法,因为post__in传空数组会被忽略导致返回全部文章,塞一个不存在的 ID 0 就能安全地得到空结果。
最后提醒一点:这段代码放在 Bricks 的 PHP 查询编辑器里时,记得点 Sign code(签名代码) 按钮保存,否则代码不会生效。签名是 Bricks 对 PHP 查询的安全确认机制,防止未经验证的代码直接执行。如果编辑时报“代码未签名”的错误,回到查询编辑器重新粘贴再签名一次即可。
性能方面也放心:两个 get_posts 都带了 no_found_rows => true 和 fields => 'ids',不查总数、只取 ID,几十篇文章的站点毫秒级完成,不会拖慢页面。真正的大列表(几千篇)才需要考虑缓存,一般内容站用不到。
小结:“精选置顶 + 去重”这类需求,用两个 get_posts 分别取 ID 再合并,比写复杂 meta_query 排序直观得多。因为全程只用一个查询循环,Bricks 的筛选(Query Filters)功能也能正常叠加,不会冲突。学会了这个模式,类似“置顶 + 常规排序”的组合需求都能照搬——比如“置顶新品 + 其余按热度”,把第一个查询的排序条件换一下就行。
常见误区
两个容易踩的坑:一是忘了点「Sign code(签名代码)」——Bricks 的 PHP 查询代码不签名就不会生效,编辑时报「代码未签名」就回去重新粘贴签名一次;二是**post__in 传空数组会被忽略**从而返回全部文章,所以空结果要塞一个不存在的 ID(如 0)来安全兜底。性能上两个 get_posts 都带 no_found_rows => true 和 fields => 'ids',几十篇的站点毫秒级,只有几千篇的大列表才需要加缓存,一般内容站用不到。
常见问题(FAQ)
Q:代码放进去没效果? A:记得在 Bricks PHP 查询编辑器里点「Sign code」签名保存,未签名代码不生效。
Q:没精选文章时返回了全部?
A:post__in 传空数组会被忽略,要用 ['post__in'=>[0]] 这种「塞不存在 ID」的写法安全返回空。
Q:这个查询会拖慢页面吗?
A:两个 get_posts 都只取 ID 且关掉计数,几十篇站点毫秒级;几千篇大列表才需缓存。
Q:查询筛选器还能叠加吗? A:能,因为只用一个查询循环,Bricks 的 Query Filters 可正常叠加不冲突。
延伸阅读
- 想要现成外贸独立站模板与建站实战?看 铲子铺 chanzipu 的外贸建站教程(同用 Bricks,从零搭出能收询盘的站)
- 相关阅读:Bricks Query Loop Api Data
延伸阅读
ACF Relationship 字段 + Bricks 查询循环:显示关联文章
教程:ACF Relationship 字段 + Bricks 查询循环:显示关联文章——acf 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
tutorialBricks 查询循环按 ACF Repeater 子字段值筛选行
教程:Bricks 查询循环按 ACF Repeater 子字段值筛选行——acf 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
tutorialBricks 按 ACF Repeater 子字段排序行
教程:Bricks 按 ACF Repeater 子字段排序行——acf 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
tutorialBricks Query Loop 高亮当前文章:给循环项加 data-current 属性
教程:Bricks Query Loop 高亮当前文章:给循环项加 data-current 属性——query loop 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
