DEV Community

Андрей Викулов (VProger)
Андрей Викулов (VProger)

Posted on • Originally published at viku-lov.ru on

WordPress: ACF поле не сохраняется — чиним запись meta

WordPress: ACF поле не сохраняется — чиним запись meta

WordPress: ACF поле не сохраняется — чиним запись meta

Запрос acf поле не сохраняется wordpress обычно прилетает так: ACF-поля в админке есть, вводишь значение, жмёшь «Обновить», а потом пусто — и get_field() возвращает null или пустую строку. В конце этой инструкции: meta реально пишется в wp_postmeta, get_field() стабильно отдаёт значение, а конфликты с хуками перестают устраивать тихий саботаж.

Сниппеты по статье: ACF Save Debug (MU-plugin) · ACF save_post с проверкой autosave/revision · WP-CLI: проверка post meta для ACF · ACF update_value: нормализация значения


В чём проблема

Симптомы:

  • ACF-поля отображаются в админке.
  • После сохранения значение пропадает.
  • В базе в wp_postmeta ключа либо нет, либо он не меняется.
  • get_field('my_field', $post_id) возвращает пусто.

Самая частая причина на проде: конфликт хуков сохранения.

  • ACF сохраняет значения при acf/save_post.
  • Ваши (или чужие) функции на save_post/wp_insert_post/pre_post_update могут:
  • срабатывать на autosave или revision и перетирать meta;
  • делать wp_update_post() внутри save_post и запускать каскад «сохранился → пересохранился → перезатёрлось»;
  • вызывать update_field()/update_post_meta() в неправильный момент (до/вместо ACF-сейва);
  • чистить $_POST (да, такое тоже бывает — “безопасность” уровня «удалить данные»).

Почему autosave/revision важны: WordPress создаёт автосохранения и ревизии, и если ваш хук не фильтрует их, он сработает «не на тот пост» и/или перезапишет meta “пустым”. Для проверки есть wp_is_post_autosave() и wp_is_post_revision().

Типичный сценарий на проде: в логе нет ошибок PHP, в админке всё сохраняется “без жалоб”, но на фронте или в REST API поле пустое. Часто виноват не сам ACF, а код темы или плагина на save_post с приоритетом 10: он срабатывает в своём порядке и перезаписывает meta до или после ACF. Ещё вариант — объектный кеш (Redis/Memcached): старые значения meta кешируются, и даже при корректной записи в БД ты видишь пустое значение, пока кеш не сбросится.


Рабочее решение

Ниже — рабочий, «боевой» путь: сначала диагностируем , потом переносим вашу логику на правильный хук ACF и выключаем перезапись на autosave/revision.

1) Включаем логирование на prod без плясок

Файл: wp-config.php


define('WP\_DEBUG', true);

define('WP\_DEBUG\_LOG', true);

define('WP\_DEBUG\_DISPLAY', false);

Enter fullscreen mode Exit fullscreen mode

Дальше хватаем лог:


tail -f wp-content/debug.log

Enter fullscreen mode Exit fullscreen mode

Если у тебя Nginx + PHP-FPM — параллельно полезно смотреть error.log PHP-FPM / nginx, но debug.log обычно хватает. После правок не забудь перезагрузить PHP (или сервис PHP-FPM), иначе старый описанный конфиг не подхватится.


2) Быстрая проверка: ACF вообще отправляет данные?

Сделаем mu-plugin (так надёжнее: не отключится вместе с темой). Готовый вариант с пояснениями: сниппет «ACF Save Debug (MU-plugin)».

Файл: wp-content/mu-plugins/acf-save-debug.php

(если папки нет — создай)


<?php

/\*\*

- Plugin Name: ACF Save Debug (MU)

\*/

add\_action('acf/save\_post', function ($post\_id) {

// Логируем только админку и только реальные посты

if (!is\_admin()) return;

// ACF сохраняет значения из $\_POST['acf'] (с версии 5+).

$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);

Enter fullscreen mode Exit fullscreen mode

Что это даёт:

  • Если в логе keys пустой — ACF не получает значения (не тот экран, не тот post_id, поля disabled/readonly, конфликт JS/редактора, кастомная форма без acf_form_head() и т.д.).
  • Если keys есть , но meta не меняется — конфликт записи/перезапись ниже по цепочке.

Сохрани пост с заполненным ACF-полем и сразу открой debug.log: должна появиться строка с нужным post_id и списком ключей из $_POST['acf']. Если ключей нет — проблема на этапе отправки формы (фронт или другой плагин режет данные).


3) Проверяем, пишется ли meta в базу (WP-CLI)

Команды и порядок проверки: сниппет «WP-CLI: проверка post meta для ACF». Сначала узнаём post_id и имя поля (name). Дальше:


wp post meta list 123 --format=table

wp post meta get 123 my\_field

Enter fullscreen mode Exit fullscreen mode

WP-CLI команды по meta — официальные, стабильные.

Если поле ACF не в my_field, а хранится иначе (например, field_XXXXXXXX как reference) — ты это тоже увидишь в списке. Так можно быстро убедиться, что запись в БД вообще происходит: если после сохранения в админке в wp post meta list появляется нужный ключ с актуальным значением, значит ACF и база в порядке, а проблема может быть в кеше или в месте, откуда ты читаешь поле.


4) Убираем конфликт: переносим вашу логику с save_post на acf/save_post

Если у тебя (или у темы/плагина) есть код вроде этого:


add\_action('save\_post', function ($post\_id) {

update\_post\_meta($post\_id, 'my\_field', $\_POST['something'] ?? '');

});

Enter fullscreen mode Exit fullscreen mode

…то он легко убьёт ACF, потому что:

  • сработает на autosave/revision;
  • может записать пустоту раньше/позже ACF;
  • может триггерить пересохранение.

Правильная точка интеграции для ACF-полей — acf/save_post. Готовый MU-plugin с проверкой autosave/revision и примером update_field: сниппет «ACF save_post с проверкой autosave/revision».

Файл: wp-content/mu-plugins/acf-save-fix.php


<?php

/\*\*

- Plugin Name: ACF Save Fix (MU)

\*/

// 20 = "после того, как ACF обработал свои данные" (часто оптимально на практике)

add\_action('acf/save\_post', function ($post\_id) {

// 1) Не трогаем автосохранения и ревизии.

if (wp\_is\_post\_autosave($post\_id) || wp\_is\_post\_revision($post\_id)) {

return;

}

// 2) На всякий — работаем только в админке

if (!is\_admin()) {

return;

}

// 3) Пример: если нужно вычислить и сохранить зависимое значение в ACF поле

// (update\_field — официальный путь для записи ACF значения).

$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);

Enter fullscreen mode Exit fullscreen mode

Ключевая идея: не мешай ACF сохраняться , а дополняй его после сейва, на acf/save_post. Приоритет 20 выбран не случайно: ACF сам вешает обработчик на acf/save_post, и к моменту срабатывания твоего кода с приоритетом 20 значения полей уже записаны в wp_postmeta. Если нужна логика “сначала ACF, потом я” — используй приоритет 20 или выше; если “сначала я, потом ACF” — приоритет меньше 10 (осторожно: не перезаписывай meta пустым).


5) Если у тебя фильтр acf/update_value — не делай там записи в БД

acf/update_value — фильтр для модификации значения перед сохранением , а не для побочных эффектов. Пример нормализации (trim, регистр) без записи в другие поля: сниппет «ACF update_value: нормализация значения».

То есть норм:


add\_filter('acf/update\_value/name=my\_field', function ($value, $post\_id, $field) {

// Нормализуем то, что сохраняем

return is\_string($value) ? trim($value) : $value;

}, 10, 3);

Enter fullscreen mode Exit fullscreen mode

А вот делать update_field() внутри acf/update_value — частый путь к рекурсии/гонкам/«то пусто, то густо». Для побочных сохранений используй acf/save_post, как выше.

6) Приоритет хука и порядок выполнения

Иногда поле сохраняется “через раз” или только при втором нажатии «Обновить». Это часто связано с тем, что несколько обработчиков висят на acf/save_post или save_post с разными приоритетами и перезаписывают друг друга. Проверь все места, где вызываются update_post_meta() или update_field() для этого поста: убедись, что они либо на acf/save_post с приоритетом не меньше 15, либо явно пропускают autosave/revision. Один “грязный” хук на приоритете 5 может обнулить meta до того, как ACF успеет записать данные.


Проверка результата

1) Проверка в админке

  • Открой пост/страницу с ACF.
  • Введи тестовое значение.
  • Сохрани.
  • Перезагрузи страницу редактирования — значение должно остаться.

Если значение пропало после перезагрузки, повтори цепочку из раздела «Рабочее решение»: проверь лог на наличие ключей в acf/save_post, затем через WP-CLI убедись, что meta есть в базе. Если в БД значение есть, а в админке пусто — возможен кеш страницы или кеш объекта (Redis/Memcached).

2) Проверка через WP-CLI


wp post meta get 123 my\_field

Enter fullscreen mode Exit fullscreen mode

Ожидаешь увидеть сохранённое значение.

3) Проверка чтения через PHP (на шаблоне/в плагине)


$value = get\_field('my\_field', 123);

var\_dump($value);

Enter fullscreen mode Exit fullscreen mode

get_field() официально возвращает значение поля из нужной “локации” (post/user/term/options) — важно, чтобы post_id был правильный. На проде после успешной записи имеет смысл один раз сбросить объектный кеш (если используется): wp cache flush через WP-CLI или сброс в панели хостинга, чтобы не ловить старые значения из кеша.


Типичные ошибки

❌ 1) Хук save_post перезаписывает meta пустым

Причина: хук срабатывает на autosave/revision или порядок хуков перетирает ACF.

Исправление: перенеси логику на acf/save_post, добавь проверки wp_is_post_autosave()/wp_is_post_revision().

❌ 2) Неверный post_id для get_field()

Причина: поле не у поста, а у options/user/term, а ты читаешь как пост.

Исправление: передай правильный post_id (например, option, user_{$id}, term_{$id} — по модели ACF) и проверь по документации get_field().

❌ 3) “Я модифицирую значение в acf/update_value, но оно не сохраняется”

Причина: ты возвращаешь null/пустоту, либо делаешь побочные записи в БД прямо в фильтре.

Исправление: в acf/update_value только возвращай нормализованное $value. Любые доп. сохранения — в acf/save_post.

❌ 4) Поле “видно”, но $_POST['acf'] пустой

Причина: кастомная форма/метабокс, конфликт JS, поле disabled/readonly, или это вообще не ACF экран.

Исправление: смотри лог mu-plugin, проверь что ACF реально сабмитит $_POST'acf'.

❌ 5) В БД meta есть, а на фронте или в API пусто

Причина: объектный кеш (Redis, Memcached, кеш плагина) отдаёт старую версию meta; или читаешь поле в неправильном контексте (например, в цикле без передачи post_id).

Исправление: выполни wp cache flush или сброс кеша в админке; при вызове get_field() всегда передавай второй аргумент — ID поста, термина или 'option'.

❌ 6) Поле внутри группы (repeater/flexible) не сохраняется

Причина: обращаешься к полю по имени без учёта группы или подполя; при ручном update_post_meta перезаписываешь сериализованные данные группы.

Исправление: используй get_field('group_name', $post_id) и вложенные ключи для подполей; для записи — только update_field() с путём к полю (например, my_repeater_0_my_subfield или через массив по документации ACF).


Если не работает: чеклист диагностики за 10 минут

  1. Убедись, что acf/save_post вообще срабатывает

Смотри wp-content/debug.log и строку вида [ACF] acf/save_post post_id=... keys=....

  1. Посмотри, кто трогает meta кроме ACF

Поиск по проекту:


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

Enter fullscreen mode Exit fullscreen mode
  1. Временно отключи подозреваемый плагин/кусок темы

На проде аккуратно: сначала на staging. Но если выбора нет — выключай точечно, не “всё подряд”.

  1. Проверь meta напрямую в БД (если есть доступ)

SELECT meta\_key, meta\_value

FROM wp\_postmeta

WHERE post\_id = 123

ORDER BY meta\_id DESC;

Enter fullscreen mode Exit fullscreen mode
  1. Проверь, что читаешь то же поле, что сохраняешь

В ACF у поля есть name и key. Для update_field() можно передавать и то, и другое — документация это допускает и это часто спасает при переименованиях.

  1. Сбрось кеш

Если на сервере включён объектный кеш или кеш страниц, после исправления кода выполни сброс: wp cache flush, очистка кеша в панели хостинга или перезапуск Redis/Memcached. Иначе можно долго отлаживать “правильный” код, глядя на закешированный результат.


Где применять

  • prod — да, именно здесь чаще всего и всплывает (конфликт плагинов/хуков, кеши, кастомные сохранения). Рецепт тот же: логи, WP-CLI, перенос логики на acf/save_post и проверка приоритетов.
  • docker/staging — идеально, чтобы отловить “кто перетирает meta” до выката. Можно временно включить debug.log и поставить mu-plugin для логирования без риска для продакшена.
  • CI/CD — можно добавить быстрый smoke-тест через WP-CLI: записать meta и прочитать обратно; при падении теста сразу видно, что сохранение или чтение полей сломалось.

Сниппеты по статье: ACF Save Debug (MU-plugin) · ACF save_post с autosave/revision · WP-CLI post meta для ACF · ACF update_value: нормализация

Пара внутренних ссылок, чтобы не искать по сайту:

Read more on viku-lov.ru

Top comments (0)