Skip to content

Всё для WordPress, веб-разработки — и не только

📝 Добавление примечаний к заказу WooCommerce в письмо: полное руководство

📝 Добавление примечаний к заказу WooCommerce в письмо: полное руководство

Клиент сделал заказ, а вы оставили примечание в админке, уточнили срок доставки, добавили трек-номер или просто написали «позвонить перед отправкой». Но клиент этого не видит. Примечания к заказу WooCommerce по умолчанию живут только в админке, на боковой панели редактирования заказа. В письмах, которые уходят покупателю, их нет.

Проблема решается одним сниппетом в functions.php. Без плагинов, без правки шаблонов, чистый хук, который выводит примечания в тело письма. На практике мы используем этот подход на клиентских магазинах уже несколько лет, ни одного сбоя после обновлений WooCommerce. В этом руководстве разберём, как WooCommerce хранит заметки к заказам, какой хук использовать и как кастомизировать вывод под свои задачи.

💡 Быстрый обзор:

  • Как WooCommerce хранит примечания к заказам: тип комментария order_note и функция wc_get_order_notes()
  • Два подхода к кастомизации писем: переопределение шаблонов или хуки, какой и когда выбирать
  • Готовый сниппет для вывода примечаний в письмо о выполнении заказа с разбором каждой строки
  • Кастомизация: стилизация списка, фильтрация только клиентских заметок, поддержка plain-text писем
  • Тестирование через предпросмотр писем в админке, без спама реальным клиентам

Шаг 1: Как WooCommerce хранит примечания к заказам

WooCommerce хранит примечания как комментарии WordPress типа order_note. Каждое действие с заказом, смена статуса, refund, заметка администратора или сообщение клиенту, записывается в таблицу wp_comments с флагом comment_type = 'order_note'.

Разница между внутренними и клиентскими заметками определяется мета-полем is_customer_note. Если чекбокс «Visible in My Account» включён при добавлении заметки, WooCommerce ставит is_customer_note = true, и покупатель видит её в личном кабинете. Обычные внутренние заметки (is_customer_note = false) клиенту не показываются нигде.

С выходом High Performance Order Storage (HPOS) в WooCommerce 8.2+ заметки попали в отдельную таблицу wp_wc_order_notes. Прямые SQL-запросы к wp_comments с включённым HPOS могут возвращать пустой результат. Поэтому вместо get_comments() лучше использовать wc_get_order_notes(), она работает корректно при любом режиме хранения.

Шаг 2: Шаблоны или хуки, какой подход выбрать

У WooCommerce два пути для кастомизации писем: переопределение шаблонов и использование экшен-хуков. У каждого, свой сценарий.

Переопределение шаблонов. Вы копируете файл из woocommerce/templates/emails/ в yourtheme/woocommerce/emails/ и правите HTML напрямую. Плюс, полный контроль над разметкой. Минус, при крупных обновлениях WooCommerce ваш шаблон может разойтись с актуальной версией, и письма начнут ломаться. Документация по структуре шаблонов теперь на woocommerce.com, а не на старом docs.woothemes.com.

Хуки. Вы вешаете callback на действие woocommerce_email_order_meta, и WooCommerce сам вызывает вашу функцию в нужном месте письма. Плюс, не зависит от версий шаблонов, работает «из коробки» после обновлений ядра. Минус, вы ограничены позицией хука (он срабатывает в блоке мета-данных заказа, после таблицы с товарами).

Критерий

Шаблоны

Хуки

Контроль над разметкой

Полный

В рамках позиции хука

Устойчивость к обновлениям

Низкая

Высокая

Сложность внедрения

Выше

Ниже

Подходит для

Капитальной переделки письма

Добавления одного блока

Для нашей задачи, вывода примечаний, хука более чем достаточно. Если вам нужно полностью перекроить дизайн писем, берите шаблоны и закладывайте время на их актуализацию раз в полгода.

Шаг 3: Добавляем код в functions.php

Хук woocommerce_email_order_meta срабатывает во всех транзакционных письмах WooCommerce: подтверждение заказа, выполнение, отмена, счёт и другие. В callback передаются четыре параметра: объект заказа $order, флаг $sent_to_admin, флаг $plain_text и объект письма $email.

Разместите этот код в functions.php активной темы (или через плагин Code Snippets, безопаснее, не слетит при смене темы):

1add_action( 'woocommerce_email_order_meta', 'sd_add_order_notes_to_email', 10, 4 );
2
3function sd_add_order_notes_to_email( $order, $sent_to_admin, $plain_text, $email ) {
4 // Не ломаем plain-text версию письма
5 if ( $plain_text ) {
6 echo "\n\n" . esc_html__( 'Order Notes:', 'woocommerce' ) . "\n";
7
8 $notes = wc_get_order_notes( array(
9 'order_id' => $order->get_id(),
10 'type' => 'customer',
11 ) );
12
13 if ( empty( $notes ) ) {
14 echo esc_html__( 'No notes for this order.', 'woocommerce' ) . "\n";
15 return;
16 }
17
18 foreach ( $notes as $note ) {
19 echo '- ' . wp_strip_all_tags( $note->content ) . "\n";
20 }
21 return;
22 }
23
24 // HTML-версия: получаем только клиентские заметки
25 $notes = wc_get_order_notes( array(
26 'order_id' => $order->get_id(),
27 'type' => 'customer',
28 ) );
29
30 if ( empty( $notes ) ) {
31 return;
32 }
33
34 echo '<h2>' . esc_html__( 'Order Notes', 'woocommerce' ) . '</h2>';
35 echo '<ul class="order-notes-list" style="list-style:none;padding:0;margin:0 0 24px;">';
36
37 foreach ( $notes as $note ) {
38 $note_date = sprintf(
39 '%1$s в %2$s',
40 date_i18n( get_option( 'date_format' ), strtotime( $note->date_created ) ),
41 date_i18n( get_option( 'time_format' ), strtotime( $note->date_created ) )
42 );
43
44 printf(
45 '<li style="background:#f9f9f9;border-left:4px solid #7f54b3;padding:12px 16px;margin-bottom:10px;border-radius:0 4px 4px 0;">'
46 . '<div style="margin-bottom:4px;">%s</div>'
47 . '<small style="color:#888;">%s</small>'
48 . '</li>',
49 wp_kses_post( nl2br( $note->content ) ),
50 esc_html( $note_date )
51 );
52 }
53
54 echo '</ul>';
55}

Что здесь происходит по строкам:

  • Строка 1. Регистрируем хук с приоритетом 10 и принимаем все 4 параметра. Без 10, 4 WooCommerce передаст только первый аргумент, получите ошибку.
  • Строки 5-20. Обработка plain-text писем. Некоторые письма уходят в текстовом формате, выводим заметки списком с дефисами, без HTML.
  • Строки 24-28. wc_get_order_notes() запрашивает только клиентские заметки (type => 'customer'). Убрать фильтр, показать все заметки, включая внутренние (смена статуса, refund). Массив пуст → ничего не выводим, письмо не захламляем.
  • Строки 34-38. Форматируем дату через date_i18n(), уважает локаль сайта и настройки формата даты/времени.
  • Строки 40-48. printf() выводит каждую заметку в стилизованном блоке: фиолетовая полоса слева, светлый фон, дата снизу серым.

Код не использует внешних зависимостей и совместим с WooCommerce 3.2+ (функция wc_get_order_notes появилась именно в этой версии) и HPOS (нативная поддержка с 8.2+).

Шаг 4: Тестируем без спама клиентам

После добавления кода не ждите реальный заказ для проверки. WooCommerce даёт встроенный предпросмотр писем: WooCommerce → Настройки → Emails → нажмите на любое письмо → кнопка «Preview» внизу. Вы увидите письмо в HTML и plain-text, с настоящим заказом (берётся последний существующий). Если заказов нет, создайте тестовый вручную.

Что проверить:

  • Клиентская заметка с включённым «Visible in My Account» отображается в письме;
  • Внутренняя заметка (без галки) не отображается (если оставили type => 'customer');
  • Plain-text версия письма не сломана (переключитесь по ссылке под предпросмотром);
  • Блок с заметками не дублируется в письмах администратору (добавьте проверку if ( $sent_to_admin ) return; если нужно).

Если пользуетесь Code Snippets, достаточно деактивировать сниппет для отката. Если правили functions.php, закомментируйте или удалите код. Никаких следов в базе не остаётся.

⁉️🤔 Частые вопросы

Можно ли выводить ВСЕ примечания, а не только клиентские?

Да. Замените 'type' => 'customer' на 'type' => 'internal', получите только внутренние заметки. Уберите параметр type совсем, получите все заметки подряд. Учитывайте, что внутренние заметки могут содержать служебную информацию (ID refund, суммы), которую клиенту видеть ни к чему. Большинству магазинов достаточно 'type' => 'customer'. Если хотите разделить вывод, сделайте два блока: сначала клиентские заметки с заголовком «Комментарии к заказу», затем внутренние под заголовком «Детали выполнения» (это уже для писем администратору, флаг $sent_to_admin).

Код работает для конкретного письма или для всех сразу?

Хук woocommerce_email_order_meta срабатывает во всех транзакционных письмах: Completed Order, Processing Order, Order on Hold, Customer Invoice и так далее. Если нужно ограничить вывод только письмом о выполнении заказа, оберните код в проверку:

1> if ( 'customer_completed_order' !== $email->id ) {
2> return;
3> }
4> ```
1

plaintext

1
2 plaintext
3
4Список всех ID писем доступен в документации WooCommerce: `customer_completed_order` · `customer_processing_order` · `customer_on_hold_order` · `customer_invoice` · `customer_refunded_order` · `customer_new_account` · `new_order` · `cancelled_order` · `failed_order`.
5
6**Безопасно ли править functions.php на боевом сайте?**
7
8> Правка `functions.php` напрямую, рискованный путь. Ошибка в синтаксисе (лишняя скобка, незакрытая кавычка) кладёт весь сайт в белый экран. Безопаснее использовать плагин Code Snippets, он позволяет добавлять PHP-сниппеты через админку и автоматически отключает код с фатальной ошибкой. Альтернатива: WPCode (бесплатная версия на wordpress.org), тот же функционал плюс условная логика (только для админов, только на определённых страницах). Если всё же правите `functions.php`, сделайте бэкап файла и держите под рукой FTP-доступ. Белый экран лечится заменой `functions.php` на оригинал из бэкапа.
9
10**Примечания дублируются в письмах, что я сделал не так?**
11
12> Две вероятные причины. Первая: вы одновременно добавили код и в `functions.php`, и через плагин сниппетов, хук срабатывает дважды. Оставьте что-то одно. Вторая: тема или другой плагин уже вешают callback на этот же хук. Проверьте через поиск по коду проекта (`grep -r "woocommerce_email_order_meta" wp-content/`). Если дублирование идёт от плагина, достаточно убрать ваш код. Если от темы, оберните свой callback в `remove_action()` перед `add_action()`, чтобы гарантированно выполнялся только один обработчик.
13
14&#35;&#35; Что в итоге: стоит ли добавлять примечания в письма клиентам
15
16Прозрачность коммуникации, один из самых дешёвых способов снизить нагрузку на поддержку. Когда клиент видит в письме «Трек-номер: X123456789, доставка 15 июня», он не идёт писать в чат «а где мой заказ?». Один сниппет, ноль плагинов, пять минут на внедрение, а эффект измеряется десятками сэкономленных тикетов в месяц.
17
18Если письма уже кастомизированы через шаблоны, встройте вывод заметки прямо в шаблон, а не хук. Если пользуетесь плагином кастомизации писем (Kadence, YayMail, ShopMagic), у каждого из них есть свой механизм добавления динамических блоков, используйте его вместо кода.
19
20Попробуйте с одним типом писем (Completed Order), проверьте на тестовом заказе и через неделю оцените, стало ли меньше однотипных вопросов от клиентов. [Почти](/recomendet-startmail_com) наверняка, да.

plaintext

1