需求:按子字段排序 Repeater 行
ACF Repeater 在 Bricks 查询循环里输出时,行的顺序固定等于录入顺序——后台拖成什么样,前端就显示什么样。这通常没问题,直到客户要求“成员按姓名排”或者“课程按日期排”。
Bricks 的查询设置里没有针对 Repeater 子字段的排序选项(排序控件主要是给文章查询用的),所以正确姿势还是走 bricks/query/run 过滤器:拿到行数组,用 PHP 的 usort 自定义比较逻辑排一遍,再交还给 Bricks 渲染。整个过程不需要改动任何字段结构,也不需要迁移数据。
Step 1:准备字段组与查询循环
- ACF 字段组里建一个 Repeater 字段,比如
team_members,子字段name(text)。 - 在页面里录入若干成员(故意打乱顺序,方便验证效果)。
- 用 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(如
Ymd或Y-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,换主题、换页面都不受影响。