首页 / 中文教程 / 教程

Bricks Query Loop:精选文章置顶且不重复(PHP 查询实现)

把最新 2 篇 ACF 精选文章排到 Query Loop 最前面,其余按日期排序且不重复。一套 PHP 查询搞定:分两步取 ID、合并数组、post__in 保持顺序。

Ray Chan·2026-08-11·约 2 分钟

需求:精选置顶 + 不重复

Bricks Facebook 群里有用户求助:他想在 Bricks 的查询结果里同时显示 5 个 CPT(资源类文章),要求:

  • 查询结果前 2 条必须是不同 CPT 里最新的、被标记为 “Featured”(基于 ACF 的是/否字段)的 2 篇文章;
  • 其余结果按日期顺序继续排列,不能重复这 2 篇精选文章;
  • 精选文章永远至少 2 篇,但只有最新的 2 篇置顶,第 3、4、5 篇精选就按正常顺序出现在结果里;
  • 结果要用 Bricks 的筛选功能,所以不能用两个查询循环拼。

这类“精选置顶”需求在内容站里很常见:编辑希望把重点内容顶到列表最前面,其余按时间自然排序。难点在于“置顶的同时不能重复出现”,用两个查询循环拼的话,精选文章会同时在两个循环里出现,而且 Bricks 的 Query Filters 筛选器只作用于单个循环,无法跨循环工作。

一个查询循环、一个 PHP 查询就能解决。

核心思路:取 ID 再合并

方案分三步:

  1. 取精选:查最新 2 篇 featured 字段为 1 的文章,只要 ID。
  2. 取其余:查全部文章,用 post__not_in 排除刚才那 2 篇精选,只要 ID。
  3. 合并:把精选 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 => truefields => 'ids',不查总数、只取 ID,几十篇文章的站点毫秒级完成,不会拖慢页面。真正的大列表(几千篇)才需要考虑缓存,一般内容站用不到。

小结:“精选置顶 + 去重”这类需求,用两个 get_posts 分别取 ID 再合并,比写复杂 meta_query 排序直观得多。因为全程只用一个查询循环,Bricks 的筛选(Query Filters)功能也能正常叠加,不会冲突。学会了这个模式,类似“置顶 + 常规排序”的组合需求都能照搬——比如“置顶新品 + 其余按热度”,把第一个查询的排序条件换一下就行。

需要帮忙?

用 Bricks 建站?我接客户项目。

从快速营销站到完整的 Bricks 建站,再到从 Elementor 迁移——我都做过。本站每篇教程都来自真实项目经验。告诉我你的需求,一个工作日内回复。

  • Bricks 建站与改版
  • Elementor / Divi → Bricks 迁移
  • Bricks → Astro / headless 性能升级
  • 速度优化,PageSpeed 95+ 目标