为什么不用内置的 ACF Relationship 查询类型
Bricks 的查询循环其实内置了 ACF Relationship 查询类型——在单篇文章页面上,它可以自动读取当前文章的 Relationship 字段,把关联的文章列出来,零代码就能用。那为什么还要折腾 PHP 查询循环?
因为内置类型能做的很有限:你没法精细控制排序规则(比如按关联字段本身的手动顺序之外的方式排)、没法轻松叠加 meta_query、也没法在循环外拿到关联数量去做条件判断。换成 PHP 查询编辑器,一切回到你熟悉的 WP_Query 参数体系,灵活度直接拉满。
本文以“游戏(Game)和评测(Review)两个 CPT 通过 ACF Relationship 互相关联,在游戏单篇页显示其所有评测”为例,完整走一遍。
Step 1:建 CPT 与双向 Relationship 字段
- 在 ACF → Post Types 里创建
game(游戏)和review(评测)两个 CPT。 - 给每个 CPT 建字段组,各加一个 Relationship 类型字段:
gameCPT 的字段related_reviews,设置里勾选“双向关联”,目标填review的related_games字段;reviewCPT 的字段related_games,同样勾选双向关联,目标填game的related_reviews字段。
双向关联的好处:在任意一侧编辑文章时都能维护关系,而且 Bricks 查询循环自带的 ACF Relationship 类型在两侧都能用。字段的 Return Format 建议保持默认(返回文章对象数组),代码里我们会用 wp_list_pluck 取 ID,两种返回格式都能兼容。
Step 2:单篇模板里用 PHP 查询循环
- 新建类型为 Single 的模板,命名为 “Game”,编辑模板条件(Template Conditions)设为
game类型的全部单篇。 - 模板结构:第一个 Section 放 Post Title 和 Post Content;第二个 Section 放一个 “Related Review” 标题,标题下方是 Container > Block,用来承载查询循环。
- 在 Block 上启用查询循环,打开 Query editor (PHP),粘贴:
$related = get_field( 'related_reviews' );
// 没有关联评测时返回空结果
if ( empty( $related ) ) {
return [ 'post__in' => [ 0 ] ];
}
return [
'post_type' => 'review',
'post__in' => wp_list_pluck( $related, 'ID' ),
'orderby' => 'post__in',
'posts_per_page' => -1,
];
要点:
get_field( 'related_reviews' )在单篇模板里会自动读取当前文章的字段值,不需要传第二个参数;wp_list_pluck( $related, 'ID' )把返回的文章对象数组转成 ID 数组——如果字段 Return Format 设的是 ID 数组,这行可以省略,直接用$related;orderby => 'post__in'保持关联字段里手动拖拽的顺序,不会被打乱;- 空值返回
[ 'post__in' => [ 0 ] ]是 Bricks 社区的标准写法:构造一个必然查不到结果的查询,避免“没有关联时显示全部评测”的错误。
- 在循环 Block 里放 Post Title、Featured Image 等元素,输出每篇评测即可。
进阶:排序、计数与空结果处理
几个常见的升级需求:
- 标题复数处理:如果想让标题在关联数大于 1 时自动显示 “Related Reviews”(带 s),可以在循环外放一个 Basic Text,值用自定义动态标签
{bl_related_count},注册方式见本站其他自定义动态标签教程(bricks/dynamic_data/tags钩子),里面count( get_field( 'related_reviews' ) )返回数字; - 给关联文章套分页:把
posts_per_page改成一个固定值(如 6),并打开查询设置里的分页选项,Bricks 会自动处理翻页参数; - 叠加筛选:返回数组里照常加
meta_query、tax_query,和原生 WP_Query 完全一致。
小结:ACF Relationship 字段配合 PHP 查询循环,核心就三步——get_field 取出关联文章、wp_list_pluck 转成 ID 数组、post__in 交给查询。记住空值返回 post__in => [0] 这个防御写法,再配合 orderby => 'post__in' 保住手动排序,就能完全掌控“相关文章”区块的输出。同理适用于 ACF Post Object 字段(取值逻辑一致),只是字段语义上 Post Object 更偏“单选/多选指向”,Relationship 更偏“双向关系”。