首页 / 中文教程 / 教程

Bricks 按 ACF Repeater 子字段排序行

ACF Repeater 的行默认按录入顺序输出,想按某个子字段字母序或日期排序?bricks/query/run 过滤器里 usort 一行搞定,不碰构建器、不用改数据结构。

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

需求:按子字段排序 Repeater 行

ACF Repeater 在 Bricks 查询循环里输出时,行的顺序固定等于录入顺序——后台拖成什么样,前端就显示什么样。这通常没问题,直到客户要求“成员按姓名排”或者“课程按日期排”。

Bricks 的查询设置里没有针对 Repeater 子字段的排序选项(排序控件主要是给文章查询用的),所以正确姿势还是走 bricks/query/run 过滤器:拿到行数组,用 PHP 的 usort 自定义比较逻辑排一遍,再交还给 Bricks 渲染。整个过程不需要改动任何字段结构,也不需要迁移数据。

Step 1:准备字段组与查询循环

  1. ACF 字段组里建一个 Repeater 字段,比如 team_members,子字段 name(text)。
  2. 在页面里录入若干成员(故意打乱顺序,方便验证效果)。
  3. 用 Bricks 编辑页面,在 Block 上启用查询循环,查询类型选该 ACF Repeater 字段,循环内用 Basic Text 输出 {acf_name}

前端此刻按录入顺序显示。接下来排序。

Step 2:usort 按子字段排序

把下面代码加到子主题 functions.php 或代码片段插件:

add_filter( 'bricks/query/run', function( $results, $query, $query_type ) {
  // 只处理 ACF Repeater 类型的查询
  if ( $query_type !== 'acf-repeater' || empty( $results ) ) {
    return $results;
  }

  usort( $results, function( $a, $b ) {
    return strcmp( $a['name'], $b['name'] );
  } );

  return $results;
}, 10, 3 );

要点:

  • usort 是 PHP 内置排序函数,第二个参数是自定义比较函数:返回负数表示 $a 在前,正数表示 $b 在前,0 表示相等。strcmp( $a['name'], $b['name'] ) 就是标准的字符串升序比较;
  • 每行 $results 元素仍然是子字段名 => 值的关联数组,所以 $a['name'] 直接取到姓名;
  • 想降序?把两个参数对调:strcmp( $b['name'], $a['name'] ),或者比较结果取负。

数字与日期子字段的排序变体

strcmp 只适合字符串。如果子字段是 number 或 date 类型,要用对应的比较方式,否则会出现“10 排在 2 前面”这类字典序错误:

// 数字子字段:升序
usort( $results, function( $a, $b ) {
  return (int) $a['price'] <=> (int) $b['price'];
} );

// 日期子字段:按时间戳降序(最新在前)
usort( $results, function( $a, $b ) {
  return strtotime( $b['start_date'] ) <=> strtotime( $a['start_date'] );
} );

两个提醒:

  • 统一格式:ACF 日期选择器记得在字段设置里固定 Return Format(如 YmdY-m-d),保证所有行格式一致,strtotime 才能正确解析;
  • 空值兜底:如果有行的子字段没填,比较时会报错或排到不可预测的位置。稳妥做法是先做空值判断,比如 if ( empty( $a['name'] ) ) return 1;,让空值统一沉底。

多级排序与作用范围

现实需求往往是“先按部门、再按姓名”这种多级排序,usort 天然支持——比较函数里先比第一键,相等再比第二键:

usort( $results, function( $a, $b ) {
  $cmp = strcmp( $a['department'], $b['department'] );
  if ( $cmp !== 0 ) {
    return $cmp; // 第一键:部门
  }
  return strcmp( $a['name'], $b['name'] ); // 第二键:姓名
} );

两个容易忽略的点:

  • 作用范围:过滤器挂上后,对所有 ACF Repeater 类型的查询循环生效。多个 Repeater 循环需要不同排序时,和筛选篇一样用 $query['element_id'] 区分($query['element_id'] !== 'brxe-xxxx' 就返回原结果);
  • 性能usort 发生在查询结果返回后,只对当前页已加载的行排序,不额外发数据库请求。Repeater 行数通常几十以内,性能开销可以忽略;上万行的极端场景才需要考虑在查询层排序。

小结:Repeater 行排序就是 usort + 正确的比较函数——字符串用 strcmp,数字用 <=>(宇宙飞船运算符),日期先用 strtotime 转时间戳;多级排序就逐键比较,相等再比下一键。结合上一篇讲的 array_filter 筛选,bricks/query/run 一个钩子就能对 Repeater 行做任意“先筛后排”的组合操作,而且全部逻辑集中在 functions.php,换主题、换页面都不受影响。

需要帮忙?

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

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

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