痛点:Group 里的子字段没法直接排序
Meta Box 的 Group 字段把多个子字段打包成一个逻辑单元,比如活动(Event)CPT 里有个 Group 字段 event_group,里面是 event_year(number)子字段。需求很常见:按年份排活动。
如果年份是个顶层字段,Bricks 查询设置的 Order by 里选“Meta 数字值”就完事了。但字段一旦包在 Group 里,排序控件就不认了——Order by 只能指向独立的 meta 键,而 Group 子字段的数据形态(尤其是可克隆 Group)不在控件能处理的范围里。
好在 Bricks 提供了 bricks/query/result 过滤器:它在查询跑完之后、渲染之前拦截结果对象,我们可以拿到文章数组,自己排序,再把排好的数组塞回去。官方查询控件管不了的排序,PHP 都能管。
Step 1:查询设置里的准备
- 在 Section 的 Container 里放一个 Posts 元素,或在一个 Block 上启用查询循环。
- 查询设置:Post type 选 Events(活动);如果模板已经应用于
event归档页可以省略。Order by 设为 “Meta 数字值”,Meta key 填event_group(这一步的意义后面讲)。 - 先把基础查询跑通,前端按默认顺序(通常是日期倒序)显示。
Step 2:bricks/query/result 重排结果
把下面代码加到子主题 functions.php 或代码片段插件:
add_filter( 'bricks/query/result', function( $result, $query, $query_type ) {
// 只处理文章查询
if ( $query_type !== 'posts' || empty( $result->posts ) ) {
return $result;
}
// 1. 取出结果里的文章 ID 数组
$ids = wp_list_pluck( $result->posts, 'ID' );
// 2. 用自定义比较函数排序(年份降序,空值沉底)
usort( $ids, function( $a, $b ) {
$av = bl_get_group_year( $a );
$bv = bl_get_group_year( $b );
if ( $av === 0 && $bv === 0 ) {
return 0;
}
if ( $av === 0 ) {
return 1; // a 没填年份 → 排后面
}
if ( $bv === 0 ) {
return -1; // b 没填年份 → 排后面
}
return $bv <=> $av; // 都有年份:降序(大年份在前)
} );
// 3. 用排序后的 ID 重建文章对象数组,塞回结果对象
$result->posts = array_map( 'get_post', $ids );
return $result;
}, 10, 3 );
// 从 Group 字段里取出年份子字段值(兼容单例与可克隆两种形态)
function bl_get_group_year( $post_id ) {
$group = rwmb_meta( 'event_group', [ 'object_type' => 'post' ], $post_id );
if ( ! is_array( $group ) ) {
return 0;
}
// 可克隆 Group:数组套数组,取第一行
$first = reset( $group );
if ( is_array( $first ) && isset( $first['event_year'] ) ) {
return (int) $first['event_year'];
}
// 普通 Group:子字段 => 值 的关联数组
if ( isset( $group['event_year'] ) ) {
return (int) $group['event_year'];
}
return 0;
}
排序逻辑详解与扩展
整个流程就是原文教程说的五步:拿文章对象数组 → 拿 ID 数组 → 自定义比较函数排序 → 用排好的 ID 重建文章对象 → 把 posts 属性写回结果对象。几个细节:
bricks/query/result参数:$result是一个 WP_Query 实例(不是结果数组!),文章列表在$result->posts;$query是查询配置;$query_type是查询类型。改完posts后直接返回同一个对象即可;- 为什么 Order by 要设 Meta 数字值:排序控件虽然排不了子字段,但能让查询结果按“存在该 meta 的文章”分组聚合,配合
$result->posts覆盖实现最终顺序。如果你发现部分文章没进结果,先检查这一步; - 比较函数语义:返回负数表示
$a在前。$bv <=> $av是“宇宙飞船运算符”的降序写法,等价于$av > $bv ? -1 : 1; - 升序:把最后一行改成
$av <=> $bv即可;想要“没填年份的也按日期倒序排”,保留空值沉底逻辑就行——沉底后的相对顺序由原查询的日期倒序天然维持; rwmb_meta读取形态:普通 Group 返回子字段 => 值的关联数组;可克隆 Group 返回“每行一个关联数组”的数组。上面的辅助函数两种都兼容,这是 Group 子字段排序最容易写错的地方。
小结:Group 子字段排序 = 查询控件排不了的部分交给 bricks/query/result 在结果层兜底。核心三步:wp_list_pluck 取 ID、usort 自定义比较、array_map( 'get_post', $ids ) 重建后写回 $result->posts。这套方法对 Group 里的 number、date、text 子字段都通用,换成日期就先把值 strtotime 转时间戳再比较,思路完全一致。