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 і так далі. Якщо потрібно обмежити вивід лише листом про виконання замовлення, оберніть код у перевірку:

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

Список усіх 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.

Чи безпечно правити functions.php на робочому сайті?

Правка functions.php напряму, ризикований шлях. Помилка в синтаксисі (зайва дужка, незакрита лапка) кладе весь сайт у білий екран. Безпечніше використовувати плагін Code Snippets, він дозволяє додавати PHP-сніпети через адмінку і автоматично вимикає код з фатальною помилкою. Альтернатива: WPCode (безкоштовна версія на wordpress.org), той самий функціонал плюс умовна логіка (лише для адмінів, лише на певних сторінках). Якщо все ж правите functions.php, зробіть бекап файлу і тримайте під рукою FTP-доступ. Білий екран лікується заміною functions.php на оригінал з бекапу.

Примітки дублюються в листах, що я зробив не так?

Дві ймовірні причини. Перша: ви одночасно додали код і в functions.php, і через плагін сніпетів, хук спрацьовує двічі. Залиште щось одне. Друга: тема або інший плагін уже вішають callback на цей самий хук. Перевірте через пошук по коду проекту (grep -r "woocommerce_email_order_meta" wp-content/). Якщо дублювання йде від плагіна, достатньо прибрати ваш код. Якщо від теми, оберніть свій callback у remove_action() перед add_action(), щоб гарантовано виконувався лише один обробник.

Що в підсумку: чи варто додавати примітки в листи клієнтам

Прозорість комунікації, один із найдешевших способів знизити навантаження на підтримку. Коли клієнт бачить у листі «Трек-номер: X123456789, доставка 15 червня», він не йде писати в чат «а де моє замовлення?». Один сніпет, нуль плагінів, п'ять хвилин на впровадження, а ефект вимірюється десятками зекономлених тікетів на місяць.

Якщо листи вже кастомізовані через шаблони, вбудуйте вивід замітки прямо в шаблон, а не хук. Якщо користуєтеся плагіном кастомізації листів (Kadence, YayMail, ShopMagic), у кожного з них є свій механізм додавання динамічних блоків, використовуйте його замість коду.

Спробуйте з одним типом листів (Completed Order), перевірте на тестовому замовленні і через тиждень оцініть, чи стало менше однотипних питань від клієнтів. Майже напевно, так.