WooCommerce hooks: 6 прикладів для товару, кошика і магазину

WooCommerce hooks: схема хуків сторінки товару

WooCommerce hooks дозволяють змінити майже будь-яку частину магазину, не чіпаючи файли плагіна. Клієнт просить «додати рядок про доставку під кнопкою» або «прибрати поле Компанія з оформлення замовлення», і перша думка зазвичай про плагін. Але здебільшого вистачає 5–10 рядків коду.

Нижче те, чим я користуюся в проєктах: як влаштовані хуки, WooCommerce single product hooks з пріоритетами, хуки кошика й сторінки магазину, найкорисніші фільтри, шість робочих прикладів і кілька помилок, на яких я сам колись втрачав час.

Action і filter: у чому різниця

Хук — це місце в коді, де WordPress або WooCommerce дозволяє вам щось втрутитись. Їх два види.

Action — «зроби щось у цьому місці». Наприклад, вивести блок тексту. Він нічого не повертає, просто виконується.

Filter — «ось значення, змін його і поверни». Наприклад, текст кнопки або список полів форми. Фільтр обов’язково має повертати значення, інакше воно зникне.

Для обох працює той самий принцип: add_action() або add_filter() з назвою хука, вашою функцією і пріоритетом. Чим менше число пріоритету, тим раніше спрацює функція. За замовчуванням це 10.

Куди писати код

Не в основну тему і не в плагін WooCommerce, бо після оновлення все зникне. Є три нормальні варіанти:

  • дочірня тема (файл functions.php);
  • власний невеликий плагін на один файл;
  • плагін на кшталт Code Snippets, якщо код потрібен лише на одному сайті і ви не хочете створювати файли.

Для клієнтських сайтів я роблю окремий плагін. Тоді код не залежить від теми, і якщо тему змінять, магазин не зламається.

Хуки сторінки товару (WooCommerce single product hooks)

Сторінка окремого товару збирається з кількох хуків. Ось ті, що потрібні найчастіше, разом з тим, що WooCommerce вішає на них за замовчуванням:

ХукПріоритетЩо виводиться
woocommerce_before_single_product_summary10 / 20Мітка знижки / галерея
woocommerce_single_product_summary5Назва
woocommerce_single_product_summary10Рейтинг, ціна
woocommerce_single_product_summary20Короткий опис
woocommerce_single_product_summary30Кнопка «Додати в кошик»
woocommerce_single_product_summary40Артикул, категорії, мітки
woocommerce_single_product_summary50Хук для кнопок «поділитися» (за замовчуванням порожній)
woocommerce_after_single_product_summary10 / 15 / 20Вкладки / апсейли / схожі товари

Також корисні woocommerce_before_add_to_cart_button і woocommerce_after_add_to_cart_button: вони стоять просто навколо кнопки.

Те саме у вигляді схеми, у порядку, в якому збирається сторінка:

woocommerce_before_single_product
├─ woocommerce_before_single_product_summary
│    10 мітка знижки · 20 галерея
├─ woocommerce_single_product_summary
│    5 назва · 10 рейтинг · 10 ціна · 20 короткий опис
│    30 додати в кошик · 40 метадані · 50 «поділитися»
├─ woocommerce_after_single_product_summary
│    10 вкладки · 15 апсейли · 20 схожі товари
└─ woocommerce_after_single_product

Одна деталь, про яку часто забувають. Якщо у вас блокова тема і шаблон товару зібраний з блоків (а не з класичного шаблону WooCommerce), частина цих хуків просто не спрацює, бо блоки їх не викликають. Це легко перевірити: додайте тестовий echo на хук і подивіться на сторінці. Якщо нічого не з’явилось, або використовуйте блок «Classic Template» у шаблоні, або змінюйте вивід через фільтр render_block.

Приклад 1. Рядок про доставку під кнопкою

Пріоритет 35 стоїть між кнопкою (30) і метаданими (40), тож рядок з’явиться одразу під кнопкою.

add_action( 'woocommerce_single_product_summary', 'dd_delivery_note', 35 );

function dd_delivery_note() {
    echo '<p class="delivery-note">Відправляємо Новою поштою в день замовлення до 15:00.</p>';
}

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

Приклад 2. Перенести блок в інше місце

Короткий опис за замовчуванням іде над кнопкою. Щоб показати його нижче за метадані, треба зняти стандартний хук і повісити його з новим пріоритетом.

add_action( 'init', 'dd_move_excerpt' );

function dd_move_excerpt() {
    remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_excerpt', 20 );
    add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_excerpt', 45 );
}

Важливо: remove_action має використовувати те саме ім’я функції і той самий пріоритет, що й оригінальний add_action. Інакше нічого не станеться, і помилки ви не побачите. Саме тому я зазвичай запускаю його на init, коли WooCommerce вже зареєстрував свої хуки.

Хуки кошика (WooCommerce cart page hooks)

На сторінці кошика хуків менше, але їх вистачає для типових задач: повідомлення над таблицею, примітка біля підсумку, текст перед кнопкою оформлення.

ХукЩо виводиться
woocommerce_before_cartПеред усією формою кошика
woocommerce_before_cart_tableНад таблицею товарів
woocommerce_after_cart_tableПід таблицею товарів
woocommerce_cart_collateralsCross-sell і блок підсумку
woocommerce_before_cart_totalsНад підсумком
woocommerce_proceed_to_checkoutКнопка оформлення (пріоритет 20)
woocommerce_after_cartПісля всього кошика

Приклад 3. Примітка над кнопкою оформлення

add_action( 'woocommerce_proceed_to_checkout', 'dd_cart_note', 5 );

function dd_cart_note() {
    echo '<p class="cart-note">Безкоштовна доставка від 2000 грн.</p>';
}

Сама кнопка висить із пріоритетом 20, тому пріоритет 5 ставить примітку над нею. Це працює для класичного кошика (шорткод). Якщо на сторінці кошика стоїть блок Cart, ці хуки не діють, тому спершу перевірте, що саме у вас.

Хуки сторінки магазину (WooCommerce shop page hooks)

Сторінки магазину й категорій працюють через цикл: однаковий набір хуків виконується для кожної картки товару. Тому зміни тут впливають на всі товари у списку.

ХукПріоритетЩо виводиться
woocommerce_before_main_content10 / 20Початок обгортки / хлібні крихти
woocommerce_archive_description10Опис категорії
woocommerce_before_shop_loop20 / 30Кількість результатів / сортування
woocommerce_before_shop_loop_item10Відкриває посилання товару
woocommerce_shop_loop_item_title10Назва товару
woocommerce_after_shop_loop_item_title5 / 10Рейтинг / ціна
woocommerce_after_shop_loop_item5 / 10Закриває посилання / кнопка «Додати в кошик»
woocommerce_after_shop_loop10Пагінація

Приклад 4. Примітка про наявність під ціною в каталозі

add_action( 'woocommerce_after_shop_loop_item_title', 'dd_loop_stock_note', 15 );

function dd_loop_stock_note() {
    global $product;
    if ( $product->is_in_stock() ) {
        echo '<span class="stock-note">В наявності, відправка сьогодні</span>';
    }
}

Ціна виводиться з пріоритетом 10, тому 15 ставить примітку одразу під нею.

Фільтри WooCommerce (WooCommerce filter hooks)

Фільтри змінюють значення: текст, HTML, масиви. Ось ті, які я використовую найчастіше:

ФільтрЩо змінює
woocommerce_get_price_htmlHTML ціни
woocommerce_product_single_add_to_cart_textТекст кнопки на сторінці товару
woocommerce_product_add_to_cart_textТекст кнопки в каталозі й категоріях
woocommerce_product_tabsВкладки товару: додати, прибрати, змінити порядок
woocommerce_checkout_fieldsПоля форми оформлення (класичний checkout)

Приклад 5. Змінити текст кнопки

add_filter( 'woocommerce_product_single_add_to_cart_text', 'dd_add_to_cart_text', 10, 2 );

function dd_add_to_cart_text( $text, $product ) {
    if ( $product->is_type( 'simple' ) ) {
        return 'Купити';
    }
    return $text;
}

Третій аргумент 10 — пріоритет, четвертий 2 — скільки параметрів функція приймає. Без нього $product не буде передано.

Так само працює і з вкладками. Наприклад, щоб прибрати вкладку «Відгуки»:

add_filter( 'woocommerce_product_tabs', 'dd_remove_reviews_tab', 98 );

function dd_remove_reviews_tab( $tabs ) {
    unset( $tabs['reviews'] );
    return $tabs;
}

Приклад 6. Прибрати зайві поля на checkout

Для українського магазину поля «Компанія» і «Адреса 2» зазвичай не потрібні. Індекс теж часто лишній, якщо доставка Новою поштою.

add_filter( 'woocommerce_checkout_fields', 'dd_checkout_fields' );

function dd_checkout_fields( $fields ) {
    unset( $fields['billing']['billing_company'] );
    unset( $fields['billing']['billing_address_2'] );
    unset( $fields['billing']['billing_postcode'] );
    return $fields;
}

Два застереження. По-перше, якщо ви рахуєте податки чи доставку за індексом, його прибирати не можна. По-друге, цей фільтр працює для класичного оформлення замовлення (шорткод). У нових магазинах WooCommerce за замовчуванням ставить блок Checkout, і там поля змінюються інакше, через власний API блоку. Перед тим як писати код, відкрийте сторінку оформлення і подивіться, яка в вас версія.

Як знайти потрібні WooCommerce hooks

Вгадувати назви не треба.

  1. Встановіть плагін Query Monitor. У ньому є вкладка «Hooks & Actions», де видно, які хуки спрацювали на поточній сторінці і які функції на них висять.
  2. Відкрийте файл шаблону в папці woocommerce/templates/ і пошукайте do_action(. Це і є всі місця, де можна втрутитись.
  3. Для довідки є офіційний перелік хуків WooCommerce у code reference.

Помилки, яких варто уникати

  • Код у файлах плагіна WooCommerce або в основній темі. Після оновлення він зникне.
  • Не той пріоритет. Якщо блок з’являється не там, де очікували, майже завжди проблема в числі.
  • echo у фільтрі. Фільтр повинен повертати значення через return, а не виводити його.
  • Вивід без екранування. Якщо текст береться з поля чи з користувача, використовуйте esc_html() або wp_kses_post().
  • Перевірка тільки у своєму браузері. Закешована сторінка може показувати стару версію. Очистіть кеш і перевірте без входу в адмінку.
  • Правки без бекапу. Помилка в functions.php може покласти сайт, тож майте свіжу копію і будьте готові прибрати сніпет через FTP.

Підсумок

WooCommerce hooks — найпростіший спосіб змінити магазин без зайвих плагінів: менше коду, менше навантаження, менше ризиків при оновленнях. Якщо вам потрібна доробка магазину або створення інтернет-магазину з нуля, дивіться як я роблю інтернет-магазини на WooCommerce. А як блокова тема змінює підхід до шаблонів, описано в гайді про Full Site Editing.