首页 / 中文教程 / 教程

Bricks 按 Meta Box Group 子字段排序文章

Order by 控件只能按顶层自定义字段排序,字段一旦包在 Group 里就没辙了。用 bricks/query/result 过滤器在结果层重排:取 ID、按子字段值比较、重建文章对象,有值的排前面,空值沉底。

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

痛点: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:查询设置里的准备

  1. 在 Section 的 Container 里放一个 Posts 元素,或在一个 Block 上启用查询循环。
  2. 查询设置:Post type 选 Events(活动);如果模板已经应用于 event 归档页可以省略。Order by 设为 “Meta 数字值”,Meta key 填 event_group(这一步的意义后面讲)。
  3. 先把基础查询跑通,前端按默认顺序(通常是日期倒序)显示。

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 转时间戳再比较,思路完全一致。

需要帮忙?

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

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

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