
本文详解 acf 中更新深层嵌套 group 字段(如「工作时间」中「周一→上午」)的正确方法,指出 `update_sub_field()` 在非 repeater 场景下的误用,并提供结构化数组赋值与 `update_field()` 的标准实践。
在 Advanced Custom Fields(ACF)中,当字段结构包含多层嵌套的 Group 字段(而非 Repeater),开发者常误将 have_rows() / the_row() 和 update_sub_field() 用于纯 Group 嵌套场景——这是根本性误区。have_rows() 和 update_sub_field() 仅适用于 Repeater 或 Flexible Content 字段,而你的结构中:
- 'Working hours' 是顶层 Group 字段(非 Repeater)
- 'Monday'、'Tuesday' 等是其下的 子 Group 字段(非 Repeater 行)
- 'Am'、'Pm' 是最内层的普通字段(Number 类型)
因此,have_rows('field_61f453c010074') 永远返回 false(Group 不支持行迭代),导致你第一段代码完全不执行;第二段代码则因数组结构错误(将 Group 当作 Repeater 处理)而静默失败。
✅ 正确做法:将整个嵌套结构视为一个关联数组,用 update_field() 一次性写入完整结构。
✅ 正确的数据结构与写法
ACF 的 Group 字段(无论嵌套几层)在数据库中存储为扁平化的关联数组。你需要严格按字段层级构造嵌套数组,键名必须为 字段 Key(field_xxxxxxxx),而非字段名称(如 'Monday')。
以更新「周一上午」和「周一下午」为例,对应你的字段结构:
$working_hours = array(
'field_61f4570e89281' => array( // Monday Group
'field_61f4573589282' => (int) $_POST['mon_am'] ?? 0, // Am (Number)
'field_61f4574589283' => (int) $_POST['mon_pm'] ?? 0, // Pm (Number)
),
'field_61f7a30ffbcf0' => array( // Tuesday Group
'field_61f7a30ffbcf1' => (int) $_POST['tue_am'] ?? 0,
'field_61f7a30ffbcf2' => (int) $_POST['tue_pm'] ?? 0,
),
// ... 同理补充 Wednesday ~ Sunday
);
// 一次性更新顶层 Group 字段
update_field('field_61f453c010074', $working_hours, $post_id);⚠️ 注意事项:所有键名必须使用 ACF 后台显示的 字段 Key(如 field_61f4570e89281),不可用字段标签或名称;数值类型字段(如 Number)建议显式类型转换(如 (int)),避免字符串写入导致前端显示异常;若某 Group 字段为空(如用户未填周二),仍需保留该键并设为空数组 [] 或 null,否则该组数据将被清空;update_field() 要求 $post_id 有效且当前用户有编辑权限(前端表单需校验 nonce 和 capability);不要混用 update_sub_field() —— 它仅在 have_rows() 循环内对 Repeater 行生效,对静态 Group 无效。
✅ 进阶建议:提升可维护性
为避免硬编码字段 Key,推荐在主题中封装映射关系:
$group_mapping = [
'monday' => ['group' => 'field_61f4570e89281', 'am' => 'field_61f4573589282', 'pm' => 'field_61f4574589283'],
'tuesday' => ['group' => 'field_61f7a30ffbcf0', 'am' => 'field_61f7a30ffbcf1', 'pm' => 'field_61f7a30ffbcf2'],
// ... 其他天
];
$working_hours = [];
foreach (['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] as $day) {
if (isset($group_mapping[$day])) {
$working_hours[$group_mapping[$day]['group']] = [
$group_mapping[$day]['am'] => (int) ($_POST["{$day}_am"] ?? 0),
$group_mapping[$day]['pm'] => (int) ($_POST["{$day}_pm"] ?? 0),
];
}
}
update_field('field_61f453c010074', $working_hours, $post_id);这样既增强可读性,又便于后期字段调整时集中维护。
总结:ACF 的 Group 字段更新本质是「结构化数组覆盖」,而非「逐行操作」。抛弃 have_rows() 思维,拥抱 update_field() + 精确字段 Key 数组,即可稳健处理任意深度的 Group 嵌套。










