Загрузка
Все статьи

WordPress REST API: где пропадает кастомное поле в сообщении о заказе WooCommerce?

Добавили кастомное поле в заказ WooCommerce через REST API — поле в админке видно, а в письме покупателя его нет. Знакомая ситуация? Разбираю, почему WooCommerce email-шаблоны игнорируют произвольные поля заказа, и показываю три способа заставить их отображаться без копипаста шаблонов.

Привет! Меня зовут Артём, я бэкенд-разработчик. Сегодня опять про REST API, но на этот раз со стороны WordPress и WooCommerce. Кейс родился из реального проекта: интернет-магазин на WooCommerce, к которому мы делали интеграцию с CRM. Менеджеры добавляли комментарий к заказу из CRM, он записывался в кастомное поле, а покупатель в email-уведомлении видел только стандартные данные — без нашего комментария.

Казалось бы, данные в заказе — они и в письме должны быть. Но WooCommerce так не думает.

Как мы добавляли кастомное поле

Через REST API всё просто — отправляем запрос на /wp-json/wc/v3/orders/{id} с нашим полем:

{
    "meta_data": [
        {
            "key": "_crm_manager_comment",
            "value": "Передана в доставку 15 мая"
        }
    ]
}

Поле сохраняется, в админке на странице заказа мы его видим (после того как добавили колонку через woocommerce_admin_order_item_headers). Но когда покупатель получает email «Заказ выполнен», кастомного поля там нет. Вообще.

Почему WooCommerce email-шаблоны «слепые» к meta_data

WooCommerce email-шаблоны жёстко закодированы. Шаблон emails/customer-completed-order.php рендерит только те данные, которые явно прописаны в нём: номер заказа, дату, позиции, итоговую сумму и billing/shipping адреса. Массив meta_data заказа в шаблоне никто не перебирает. Это сделано намеренно — WooCommerce не знает, какие из ваших кастомных полей стоит показывать покупателю, а какие — внутренние (например, ID в CRM или хэш для вебхука).

Новички часто копируют шаблон письма в свою тему (woocommerce/emails/...) и вручную дописывают вывод поля. Это работает, но создаёт проблему: при обновлении WooCommerce ваш кастомный шаблон перестанет получать улучшения безопасности и новые фичи.

Способ 1: Хук woocommerce_email_order_meta_fields (правильный)

WooCommerce предоставляет специальный хук woocommerce_email_order_meta_fields, который отрисовывает дополнительную секцию в письме с таблицей произвольных полей. Вам нужно только указать, какие ключи показывать:

add_action('woocommerce_email_order_meta_fields', function($fields, $sent_to_admin, $order) {
    $comment = $order->get_meta('_crm_manager_comment');
    if (!empty($comment)) {
        $fields['_crm_manager_comment'] = [
            'label' => __('Комментарий менеджера', 'my-theme'),
            'value' => esc_html($comment),
        ];
    }
    return $fields;
}, 10, 3);

Этот подход не требует копирования шаблонов. Поля появятся в разделе «Custom fields» в каждом email-шаблоне заказа. Минус — вы не можете контролировать позицию: секция всегда рендерится после таблицы товаров и перед totals.

Способ 2: Хук woocommerce_order_details_after_order_table

Если вам нужно больше контроля над разметкой, используйте хук для встраивания произвольного HTML:

add_action('woocommerce_order_details_after_order_table', function($order) {
    $comment = $order->get_meta('_crm_manager_comment');
    if (empty($comment)) return;
    
    echo '<h2>' . __('Комментарий менеджера', 'my-theme') . '</h2>';
    echo '<p style="margin: 0 0 20px; color: #555;">' . esc_html($comment) . '</p>';
}, 10, 1);

Этот хук срабатывает и в email, и на странице «Мой аккаунт» (страница просмотра заказа). Если хотите, чтобы кастомный блок появлялся только в email, используйте проверку:

add_action('woocommerce_order_details_after_order_table', function($order) {
    // Проверяем, что мы в контексте email
    if (!is_email_context()) return;
    // ...
});

Однако is_email_context() работает не всегда надёжно. Более надёжный способ — проверить наличие глобальной переменной $email:

global $email;
if (!$email instanceof WC_Email) return;

Способ 3: Кастомный email-шаблон (только если нужно кардинально изменить layout)

Если ни один из хуков не даёт нужного результата, можно скопировать шаблон в тему и отредактировать его напрямую. Скопируйте wp-content/plugins/woocommerce/templates/emails/customer-completed-order.php в wp-content/themes/your-theme/woocommerce/emails/customer-completed-order.php. После этого добавьте вывод поля в нужном месте шаблона.

Важно: при обновлении WooCommerce система не перезапишет ваш файл, но и не уведомит о том, что оригинальный шаблон изменился. Рекомендую установить плагин WooCommerce Template Status Checker или регулярно сравнивать ваши шаблоны с оригинальными после обновлений.

Проблема с кэшированием meta_data

Ещё одна грабля, с которой я столкнулся: если вы обновляете meta_data через REST API, а email уже стоит в очереди на отправку (WooCommerce ставит email в очередь через wp_cron), заказ может быть прочитан из object cache до вашего обновления. WooCommerce кэширует объекты заказов внутри текущего запроса.

Решение: после обновления заказа через API вызовите wp_cache_delete($order_id, 'posts') или используйте метод wc_delete_shop_order_transients($order_id) для полной очистки кэша заказа. Без этого покупатель получит email с устаревшими данными.

Поделиться статьёй

Комментарии

0
0 / 2000

Пока нет комментариев

Будьте первым, кто оставит комментарий к этой статье

Читайте также

WordPress: REST API и кастомные эндпоинты без плагинов

Для интеграции WordPress с мобильным приложением понадобилось создать кастомные REST-эндпоинты. Плагины типа ACF to REST API не подходили — нужна была специфическая логика: фильтрация по пользовательским полям, пагинация, кэширование. Сделали всё через register_rest_route и шорткоды — без единого плагина.

26 мая 2026 8 мин

WordPress Gutenberg: custom-блоки без JavaScript — как создать блок через PHP

Все гайды по Gutenberg-блокам заставляют писать React и собирать через wp-scripts. Но что если вы backend-разработчик и не хотите тащить node_modules в проект? В WordPress 5.9+ появилась возможность регистрировать серверные блоки полностью на PHP. Разбираю этот подход.

6 мая 2026 7 мин

Сложности с разделами каталога в Битрикс24 через REST API: игра с деревом

Обновляете товар через API, передаете SECTION_ID, но он не появляется в нужной папке. В этой статье я объясняю разницу между простым SECTION_ID и сложным деревом инфоблоков, как правильно выстроить иерархию и почему метод crm.product.update не умеет создавать папки.

5 июля 2026 1 мин