← Назад в блог

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

ACF поле отображается, но после сохранения пусто. Пошаговое решение: проверка autosave/revision, перенос логики на acf/save_post, код и диагностика через WP-CLI и debug.log.

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

Требования

  • WordPress 6.x
  • ACF (Free/Pro) установлен и активен
  • Доступ к WP-CLI и логам на prod

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

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

tail -f wp-content/debug.log

Если у тебя 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);

Что это даёт:

  • Если в логе 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

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'] ?? '');
});

…то он легко убьёт 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);

Ключевая идея: не мешай 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);

А вот делать 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

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

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

$value = get_field('my_field', 123);
var_dump($value);

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'] (в ACF 5+ это именно 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=....

  2. Посмотри, кто трогает 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
  1. Временно отключи подозреваемый плагин/кусок темы На проде аккуратно: сначала на staging. Но если выбора нет — выключай точечно, не “всё подряд”.

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

SELECT meta_key, meta_value
FROM wp_postmeta
WHERE post_id = 123
ORDER BY meta_id DESC;
  1. Проверь, что читаешь то же поле, что сохраняешь В ACF у поля есть name и key. Для update_field() можно передавать и то, и другое — документация это допускает и это часто спасает при переименованиях.

  2. Сбрось кеш Если на сервере включён объектный кеш или кеш страниц, после исправления кода выполни сброс: 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: нормализация

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

0 просмотров

Комментарии

Загрузка комментариев...
Пока нет комментариев. Будьте первым!