WordPress: ACF поле не сохраняется — чиним запись meta
ACF поле отображается, но после сохранения пусто. Пошаговое решение: проверка autosave/revision, перенос логики на acf/save_post, код и диагностика через WP-CLI и debug.log.
Требования
- WordPress 6.x
- ACF (Free/Pro) установлен и активен
- Доступ к WP-CLI и логам на prod
WordPress: ACF поле не сохраняется — чиним запись meta
Запрос acf поле не сохраняется wordpress обычно приходит так: поля ACF в админке есть, вы вводите значение, нажимаете «Обновить», а в базе и в get_field() — пусто. Проблема одна: значение ACF не попадает в wp_postmeta или перезаписывается. Причины — конфликт хуков save_post и acf/save_post, срабатывание на autosave/revision, неверный nonce или приоритет хука. Ниже: как продиагностировать и исправить кодом (путь к файлам, минимум три блока кода, проверка через WP-CLI). Если вы пишете свои метаполя без ACF, сценарий другой — см. сущности WordPress и свои поля в functions.php.
В чём проблема
Симптомы:
- ACF-поля отображаются в админке.
- После нажатия «Обновить» значение пропадает.
- В таблице
wp_postmetaнужного ключа нет или он не обновляется. get_field('my_field', $post_id)возвращаетnullили пустую строку.
Почему возникает:
- Конфликт хуков — ACF сохраняет данные на
acf/save_post. Код темы или плагинов наsave_post/wp_insert_post/pre_post_updateможет срабатывать на автосохранении или ревизии и перетирать meta пустым значением, либо вызыватьwp_update_post()и запускать повторное сохранение. - Autosave и revision — WordPress создаёт автосохранения и ревизии; если хук не отфильтрует их через
wp_is_post_autosave($post_id)иwp_is_post_revision($post_id), обработчик может записать meta «не в тот» пост или перезаписать уже сохранённое ACF. - Приоритет хука — несколько обработчиков на
acf/save_postилиsave_postс разными приоритетами могут перезаписывать друг друга; один вызов с приоритетом 5 способен обнулить meta до записи ACF. - Фильтр
acf/update_value— если внутри него вызыватьupdate_field()или писать в БД, возможны рекурсия и нестабильное сохранение. - Объектный кеш (Redis/Memcached) — в БД значение есть, а при чтении отдаётся старый закешированный вариант.
Типичный сценарий на проде: в логе PHP ошибок нет, в админке «всё сохраняется», а на фронте или в API поле пустое — виноват порядок хуков или кеш.
Как отличить от «своих» полей без ACF: если вы не используете ACF, а пишете метабокс вручную через add_meta_box и save_post, сценарий другой — см. статью сущности WordPress и свои поля в functions.php. Там разобраны nonce, register_post_meta и отсечение autosave для нативного API. Здесь речь только про поля, созданные в интерфейсе ACF (Field Group), которые сохраняются плагином через acf/save_post.
Рабочее решение
1) Включить логирование (prod/staging)
Файл: wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
Просмотр лога:
tail -f wp-content/debug.log
После изменений перезагрузите PHP-FPM или веб-сервер, чтобы подхватился конфиг.
2) Проверка: ACF отправляет данные в запросе
MU-plugin логирует факт срабатывания acf/save_post и список ключей из $_POST['acf'].
Файл: wp-content/mu-plugins/acf-save-debug.php (папку mu-plugins создайте, если нет)
<?php
/**
* Plugin Name: ACF Save Debug (MU)
*/
add_action('acf/save_post', function ($post_id) {
if (!is_admin()) {
return;
}
$keys = isset($_POST['acf']) && is_array($_POST['acf'])
? array_keys($_POST['acf'])
: [];
error_log('[ACF] acf/save_post post_id=' . $post_id . ' keys=' . implode(',', $keys));
}, 1);
Сохраните пост с заполненным ACF-полем и откройте debug.log. Если в логе keys пустые — ACF не получает данные (не тот экран, конфликт JS, форма без acf_form_head()). Если ключи есть, а meta не меняется — конфликт записи или кеш.
Готовый вариант: сниппет ACF Save Debug (MU-plugin).
3) Проверка записи в БД через WP-CLI
Подставьте свой post_id и имя поля (meta_key):
wp post meta list 123 --format=table
wp post meta get 123 my_field
Если после сохранения в админке в списке meta появляется нужный ключ с верным значением — запись в БД идёт, проблема может быть в кеше или в месте чтения. Сниппет WP-CLI: проверка post meta для ACF.
4) Убрать конфликт: перенос логики с save_post на acf/save_post
Код на save_post, который пишет или трогает meta этого поста, может перетирать ACF. Правильная точка интеграции для полей ACF — acf/save_post, с отсечением autosave и revision.
Файл: wp-content/mu-plugins/acf-save-fix.php
<?php
/**
* Plugin Name: ACF Save Fix (MU)
*/
add_action('acf/save_post', function ($post_id) {
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
if (!is_admin()) {
return;
}
$value = get_field('source_field', $post_id);
if ($value === null || $value === '') {
return;
}
$computed = mb_strtoupper((string) $value);
update_field('my_field', $computed, $post_id);
}, 20);
Приоритет 20 — после того, как ACF уже записал свои значения в wp_postmeta. Для побочных сохранений используйте только acf/save_post, не save_post. Сниппет ACF save_post с проверкой autosave/revision.
5) Не писать в БД внутри acf/update_value
acf/update_value — фильтр для изменения значения перед сохранением. Внутри него не вызывайте update_field() и не пишите в другие meta — это ведёт к рекурсии и «то пусто, то есть».
Допустимо только возвращать нормализованное значение:
add_filter('acf/update_value/name=my_field', function ($value, $post_id, $field) {
return is_string($value) ? trim($value) : $value;
}, 10, 3);
Сниппет ACF update_value: нормализация значения.
Если не работает: чеклист за 10 минут
- Проверить, что
acf/save_postсрабатывает — вdebug.logдолжна быть строка вида[ACF] acf/save_post post_id=... keys=.... - Найти весь код, который трогает meta:
grep -R "save_post" -n wp-content/themes wp-content/plugins wp-content/mu-plugins
grep -R "update_post_meta" -n wp-content/themes wp-content/plugins wp-content/mu-plugins
- Временно отключить подозрительный плагин или кусок темы (на staging).
- Проверить meta в БД:
SELECT meta_key, meta_value
FROM wp_postmeta
WHERE post_id = 123
ORDER BY meta_id DESC;
- Убедиться, что читаете то же поле, что сохраняете (name/key в ACF).
- Сбросить кеш — объектный и страниц:
wp cache flushили сброс в панели хостинга.
Проверка результата
В админке: откройте запись с ACF, введите значение, нажмите «Обновить», перезагрузите страницу редактирования — значение должно остаться.
Через WP-CLI:
wp post meta get 123 my_field
Ожидаемый вывод — сохранённая строка. Пусто — смотрите раздел «Типичные ошибки» и чеклист выше.
В коде (шаблон/плагин):
$value = get_field('my_field', 123);
var_dump($value);
Убедитесь, что передаёте правильный контекст (post_id, option, user_{id} и т.д.). После успешной записи на проде один раз выполните сброс объектного кеша.
Типичные ошибки
1. Хук save_post перезаписывает meta пустым — срабатывает на autosave/revision или раньше/позже ACF. Перенесите логику на acf/save_post, добавьте проверки wp_is_post_autosave() и wp_is_post_revision().
2. Неверный контекст для get_field() — поле привязано к options/user/term, а вы читаете как у поста. Передавайте второй аргумент: post_id, 'option', user_{$id}, term_{$id} по документации ACF.
3. В acf/update_value возвращают null или делают побочные записи в БД — в фильтре только возвращайте нормализованное $value. Дополнительные сохранения — в acf/save_post.
4. В БД meta есть, на фронте пусто — объектный кеш или кеш страницы отдаёт старое значение. Выполните wp cache flush и при вызове get_field() всегда передавайте второй аргумент (ID поста/термина или 'option').
5. Поле внутри repeater/flexible не сохраняется — обращение по имени без учёта группы или ручной update_post_meta по сериализованной группе. Используйте get_field('group_name', $post_id) и для записи только update_field() с путём к полю.
Если после всех шагов поле всё равно пустое: проверьте, что Field Group в ACF привязан к нужному типу записи и к нужному экрану (например, «Post» или ваш CPT). Убедитесь, что имя поля (Name) в ACF совпадает с тем, что вы передаёте в get_field() и update_field(). Для полей внутри repeater используйте синтаксис ACF для вложенных полей (например, my_repeater_0_my_subfield или массив по документации). На хостинге с объектным кешем после первого успешного сохранения выполните один раз wp cache flush, чтобы не смотреть на закешированное старое значение. Для полей в опциях сайта (options page) используйте второй аргумент 'option': get_field('my_field', 'option') и update_field('my_field', $value, 'option') — иначе ACF ищет значение у поста. Резюме: одна проблема — ACF поле не сохраняется; решение — диагностика через mu-plugin и WP-CLI, перенос своей логики на acf/save_post с приоритетом 20 и отсечением autosave/revision, без побочных записей в acf/update_value; проверка — админка и wp post meta get; типичные ошибки — перезапись с save_post, неверный контекст, кеш, repeater без учёта группы.
Где применять
- Prod — здесь чаще всего проявляются конфликт плагинов/хуков и кеш. Порядок тот же: логи, WP-CLI, перенос на
acf/save_post, проверка приоритетов и сброс кеша. - Docker / staging — удобно включить
debug.logи MU-plugin для логирования без риска для прода. - CI/CD — можно добавить smoke-тест через WP-CLI: записать meta и прочитать обратно; падение теста покажет сломанное сохранение или чтение полей.
Полезные ссылки по теме: WordPress Core Web Vitals 2026: ускорение без магии, блог, сниппеты.



Комментарии