
🔧 Як зробити тему WordPress готовою до WooCommerce: повне керівництво для розробників
Пишете свою тему й хочете вписати в неї магазин? Технічно WooCommerce працює з будь-якою темою — це просто плагін. Але «працює» не означає «виглядає як треба»: роз’їжджається сітка товарів, пливуть сайдбари, стандартні стилі конфліктують із вашими.
Проблема глибша за пару CSS-правил. Починаючи з WooCommerce 3.3, тема без оголошеної підтримки отримує спрощений рендеринг через шорткоди та попередження в адмінці. Повний контроль над версткою ви втрачаєте.
Нижче, готові сніпети від оголошення підтримки до живого кошика в меню. Кожен перевірено на актуальній версії WooCommerce і розбито за розділами, від фундаменту до тонкого налаштування.
💡 Швидкий огляд:
- Спочатку тема має явно заявити про підтримку WooCommerce, без цього не ввімкнуться перевизначення шаблонів і частина функцій
- Код розміщуйте в окремому файлі (наприклад
inc/woocommerce.php), який підвантажується лише за активного плагіна - Налаштування сітки магазину потребує двох фільтрів: один змінює колонки, другий додає клас на
body - Галерея товарів, зум, лайтбокс і слайдер вмикаються окремими викликами
add_theme_support - Кошик у меню має оновлюватися через AJAX, використовуйте фільтр
add_to_cart_fragments
1. Фундамент: оголошення підтримки та перевірка активності
Перше й найважливіше: тема має явно сказати WooCommerce: «я тебе підтримую». Без цього плагін не активує перевизначення шаблонів і виводить попередження в адмінці. Починаючи з WooCommerce 3.3, тема без оголошеної підтримки отримує спрощений рендеринг через шорткоди — це працює, але обмежує контроль над версткою.
1 add_action( 'after_setup_theme', function() { 2 add_theme_support( 'woocommerce' ); 3 } );
Важливо використовувати саме хук after_setup_theme, а не init, так рекомендує документація WooCommerce. З версії 3.3+ можна одразу передати налаштування сітки:
1 add_action( 'after_setup_theme', function() { 2 add_theme_support( 'woocommerce', array( 3 'thumbnail_image_width' => 150, 4 'single_image_width' => 300, 5 'product_grid' => array( 6 'default_rows' => 3, 7 'min_rows' => 2, 8 'max_rows' => 8, 9 'default_columns' => 4, 10 'min_columns' => 2, 11 'max_columns' => 5, 12 ), 13 ) ); 14 } );
Ці параметри задають значення за замовчуванням для кастомайзера (WooCommerce → Product Images / Product Catalog) і позбавляють користувача необхідності налаштовувати сітку вручну.
Перевірка активності плагіна
Коли ви віддаєте тему для розповсюдження, не можна просто скинути WooCommerce-сніпети в кінець functions.php, їх викличе фатальну помилку, якщо плагін не активний. Код має завантажуватися лише за працюючого WooCommerce:
1 define( 'MYTHEME_WOOCOMMERCE_ACTIVE', class_exists( 'WooCommerce' ) ); 2 3 if ( MYTHEME_WOOCOMMERCE_ACTIVE ) { 4 require_once get_template_directory() . '/inc/woocommerce.php'; 5 }
Константа обчислюється один раз, і далі ви в будь-якому місці теми можете обгорнути виклик в if ( MYTHEME_WOOCOMMERCE_ACTIVE ). Це чистіше, ніж щоразу смикати class_exists або is_plugin_active.
2. Керування стилями WooCommerce
WooCommerce постачається з трьома CSS-файлами: woocommerce-general, woocommerce-layout і woocommerce-smallscreen. В ідеалі ви не видаляєте їх, а перевизначаєте у своїй темі, тоді сторонні WooCommerce-розширення, які спираються на ці класи, не ламаються. Але якщо ви пишете все з нуля й хочете повного контролю, ось як їх прибрати.
Видалити всі стилі разом:
1 add_filter( 'woocommerce_enqueue_styles', '__return_empty_array' );
Або прибрати вибірково:
1 function mytheme_remove_woo_styles( $styles ) { 2 unset( $styles['woocommerce-general'] ); 3 unset( $styles['woocommerce-layout'] ); 4 unset( $styles['woocommerce-smallscreen'] ); 5 return $styles; 6 } 7 add_filter( 'woocommerce_enqueue_styles', 'mytheme_remove_woo_styles' );
На практиці частіше застосовують другий варіант: прибирають woocommerce-layout (відсоткова сітка), але залишають woocommerce-general (кнопки, повідомлення, форми) і точково перебивають їх своїм CSS із вищим пріоритетом.
3. Налаштування сторінок магазину
Скільки товарів показувати
Фільтр loop_shop_per_page керує кількістю товарів на сторінці магазину та в архівах (категорії, теги):
1 function mytheme_woo_posts_per_page( $cols ) { 2 return 12; 3 } 4 add_filter( 'loop_shop_per_page', 'mytheme_woo_posts_per_page' );
Кількість колонок у сітці
Тут потрібні два фільтри. Одного loop_shop_columns недостатньо: на відміну від шорткодів WooCommerce (які мають обгортку з класом columns-N), на сторінках магазину такого класу немає. Тому додаємо його на body:
1 function mytheme_woo_shop_columns( $columns ) { 2 return 4; 3 } 4 add_filter( 'loop_shop_columns', 'mytheme_woo_shop_columns' ); 5 6 function mytheme_woo_shop_columns_body_class( $classes ) { 7 if ( is_shop() || is_product_category() || is_product_tag() ) { 8 $classes[] = 'columns-4'; 9 } 10 return $classes; 11 } 12 add_filter( 'body_class', 'mytheme_woo_shop_columns_body_class' );
Тепер у CSS можна писати селектори .columns-4 ul.products li.product, і вони застосовуватимуться саме до сітки магазину.
Заголовок магазину
WooCommerce за замовчуванням виводить «Shop» як заголовок на сторінці магазину. Якщо ваша тема вже вміє показувати заголовки архівів, цей дублікат заважає:
1 add_filter( 'woocommerce_show_page_title', '__return_false' );
Якщо ж ви використовуєте the_archive_title(), можна підмінити заголовок на назву сторінки магазину (яку задають в адмінці):
1 function mytheme_woo_archive_title( $title ) { 2 if ( is_shop() && $shop_id = wc_get_page_id( 'shop' ) ) { 3 $title = get_the_title( $shop_id ); 4 } 5 return $title; 6 } 7 add_filter( 'get_the_archive_title', 'mytheme_woo_archive_title' );
4. Галерея товарів: зум, лайтбокс і слайдер
З версії WooCommerce 3.0 з’явилася нова галерея товарів на базі FlexSlider, PhotoSwipe та jQuery Zoom. У версіях 3.0-3.2 її вимкнено за замовчуванням, і вона потребує явного ввімкнення. Починаючи з 3.3 галерею ввімкнено для не-WooCommerce-тем і вимкнено для тем, які заявили підтримку, ви вмикаєте потрібні компоненти самостійно:
1 add_theme_support( 'wc-product-gallery-slider' ); 2 add_theme_support( 'wc-product-gallery-zoom' ); 3 add_theme_support( 'wc-product-gallery-lightbox' );
Можна ввімкнути лише частину: наприклад, слайдер і зум, так, а лайтбокс замінити власним рішенням із Fancybox. Кожна директива підвантажує свої скрипти, тому зайве краще не вмикати.
Кількість колонок у мініатюрах галереї (під основним зображенням товару):
1 function mytheme_woo_product_thumbnails_columns() { 2 return 4; 3 } 4 add_action( 'woocommerce_product_thumbnails_columns', 'mytheme_woo_product_thumbnails_columns' );
5. Супутні та продані товари (cross-sells / up-sells)
На сторінці товару WooCommerce виводить блоки «Супутні товари» (related) та «З цим також купують» (up-sells). Їхня кількість і сітка налаштовуються окремо.
Скільки супутніх товарів показувати:
1 function mytheme_woo_related_posts_per_page( $args ) { 2 $args['posts_per_page'] = 4; 3 return $args; 4 } 5 add_filter( 'woocommerce_output_related_products_args', 'mytheme_woo_related_posts_per_page' );
Колонки для up-sells і related-блоків, та сама історія, що й із сіткою магазину: змінюємо і колонки, і клас на body:
1 function mytheme_woo_single_loops_columns( $columns ) { 2 return 4; 3 } 4 add_filter( 'woocommerce_up_sells_columns', 'mytheme_woo_single_loops_columns' ); 5 6 function mytheme_woo_related_columns( $args ) { 7 $args['columns'] = 4; 8 return $args; 9 } 10 add_filter( 'woocommerce_output_related_products_args', 'mytheme_woo_related_columns', 10 ); 11 12 function mytheme_woo_single_loops_columns_body_class( $classes ) { 13 if ( is_singular( 'product' ) ) { 14 $classes[] = 'columns-4'; 15 } 16 return $classes; 17 } 18 add_filter( 'body_class', 'mytheme_woo_single_loops_columns_body_class' );
Зверніть увагу: у woocommerce_output_related_products_args два фільтри з різними пріоритетами, mytheme_woo_related_posts_per_page (за замовчуванням 10) змінює posts_per_page, а mytheme_woo_related_columns (пріоритет 10) змінює columns. Вони не конфліктують, бо працюють із різними ключами одного масиву $args.
6. Пагінація та значок розпродажу
Стрілки пагінації магазину можна замінити на іконки вашої теми:
1 function mytheme_woo_pagination_args( $args ) { 2 $args['prev_text'] = '<i class="fa fa-angle-left"></i>'; 3 $args['next_text'] = '<i class="fa fa-angle-right"></i>'; 4 return $args; 5 } 6 add_filter( 'woocommerce_pagination_args', 'mytheme_woo_pagination_args' );
Замість Font Awesome підставте свої класи іконок або прямі SVG.
Текст на значку розпродажу (Sale!) легко перевизначити, зручно для сайтів іншою мовою або просто щоб прибрати знак оклику:
1 function mytheme_woo_sale_flash() { 2 return '<span class="onsale">' . esc_html__( 'Sale', 'woocommerce' ) . '</span>'; 3 } 4 add_filter( 'woocommerce_sale_flash', 'mytheme_woo_sale_flash' );
Для української мови замініть 'Sale' на 'Скидка', переклад підхопиться автоматично, якщо у вас є MO-файли WooCommerce українською.
7. Динамічний кошик у меню
Мабуть, найзатребуваніший елемент у будь-якій магазинній темі, іконка кошика в навігації з актуальною сумою. Реалізація складається з трьох частин: додавання елемента в меню, генерація HTML кошика та AJAX-оновлення.
1 // Добавление ссылки в меню 2 function mytheme_add_menu_cart_item( $items, $args ) { 3 if ( $args->theme_location === 'primary' ) { 4 $css_class = 'menu-item menu-item-type-cart menu-item-type-woocommerce-cart'; 5 if ( is_cart() ) { 6 $css_class .= ' current-menu-item'; 7 } 8 $items .= '<li class="' . esc_attr( $css_class ) . '">'; 9 $items .= mytheme_menu_cart_item(); 10 $items .= '</li>'; 11 } 12 return $items; 13 } 14 add_filter( 'wp_nav_menu_items', 'mytheme_add_menu_cart_item', 10, 2 ); 15 16 // HTML корзины 17 function mytheme_menu_cart_item() { 18 $cart_count = WC()->cart->cart_contents_count; 19 $css_class = 'wpex-menu-cart-total wpex-cart-total-' . intval( $cart_count ); 20 $url = $cart_count ? WC()->cart->get_cart_url() : wc_get_page_permalink( 'shop' ); 21 $html = WC()->cart->get_cart_total(); 22 $html = str_replace( 'amount', '', $html ); 23 24 return '<a href="' . esc_url( $url ) . '" class="' . esc_attr( $css_class ) . '">' 25 . '<span class="cart-icon"></span>' 26 . wp_kses_post( $html ) 27 . '</a>'; 28 } 29 30 // AJAX-обновление фрагментов 31 function mytheme_menu_cart_link_fragments( $fragments ) { 32 $fragments['.wpex-menu-cart-total'] = mytheme_menu_cart_item(); 33 return $fragments; 34 } 35 add_filter( 'add_to_cart_fragments', 'mytheme_menu_cart_link_fragments' );
Критично важливий момент: **не обгортайте ці функції в **is_admin(). AJAX-запити кошика приходять через admin-ajax.php, і якщо функція недоступна в адмін-контексті, оновлення ціни в меню просто не спрацює. theme_location замініть на ідентифікатор свого меню (у прикладі primary).
8. Альтернативний підхід: шаблон woocommerce.php
Описані вище хуки, найгнучкіший і найбезпечніший з погляду оновлень метод. Але якщо вам потрібно радикально перекроїти всю обгортку магазину та продуктових сторінок, є шлях через окремий шаблон.
Створіть у корені теми файл woocommerce.php (копія page.php) і замініть головний цикл на виклик woocommerce_content():
1 <?php 2 get_header(); ?> 3 4 <div id="primary" class="content-area"> 5 <main id="main" class="site-main"> 6 <?php woocommerce_content(); ?> 7 </main> 8 </div> 9 10 <?php get_footer(); 11
Цей метод простіший, але він має свою ціну: один шаблон на всі WooCommerce-сторінки, і магазин, і категорії, і картку товару. Тонке налаштування (різну сітку, різний сайдбар на різних сторінках) робити складніше. Обирайте його, тільки якщо поточна тема зовсім не товаришує з WooCommerce на рівні розмітки, і ви готові прийняти обмеження.
⁉️🤔 Часті запитання
Чи обов’язково видаляти стандартні стилі WooCommerce?
Не обов’язково. Безпечніший шлях, залишити їх і перевизначати селектори у своїй темі з вищим пріоритетом. Так ви зберігаєте сумісність із розширеннями, які спираються на стандартні класи WooCommerce. Повне видалення (
__return_empty_array) виправдане лише тоді, коли ви пишете магазинну тему з нуля і точно знаєте, що жодні сторонні плагіни не додаватимуть елементи, стилізовані під WooCommerce. У більшості випадків достатньо вибірково вимкнутиwoocommerce-layout(відсоткова сітка конфліктує з флексбоксами та гридами сучасних тем), аwoocommerce-generalіwoocommerce-smallscreenзалишити й акуратно перебити через каскад CSS, так ви отримуєте чисту сітку без втрати сумісності.
Чому не працює зміна колонок у магазині?
Тому що самого фільтра loop_shop_columns недостатньо. WooCommerce використовує класи .columns-N на обгортці для роботи сітки, і вони автоматично додаються лише до шорткодів ([products columns="4"]). На сторінках магазину та архівах цієї обгортки немає, клас потрібно вішати на body через body_class. Два фільтри з розділу 3 повністю вирішують проблему.
Фільтр
loop_shop_columnsзмінює PHP-змінну, яку WooCommerce передає в шаблон, але CSS-сітка прив’язана до класу-обгортки. Без класуcolumns-4наbodyваші стиліul.products li.productне мають селектора-контексту й або не застосовуються, або б’ють по всіх продуктових списках на сайті.
Чи потрібно перезбирати тему після оновлення WooCommerce?
Якщо ви використовуєте хуки (усі сніпети з цієї статті), ні. Хуки змінюються вкрай рідко. Якщо ви перевизначаєте шаблони (файли з woocommerce/templates/), так, потрібно звіряти свої копії з актуальними після кожного мажорного оновлення. Саме тому офіційна документація рекомендує хуки як кращий метод кастомізації.
Хуки — це контракт. WooCommerce гарантує їхню стабільність між версіями. Шаблони — це реалізація, яка може змінитися будь-якої миті: додадуться нові екшени, зміниться розмітка, перейменуються класи. За п’ять років існування хуків
loop_shop_columnsіwoocommerce_output_related_products_argsїхня сигнатура не змінювалася жодного разу, а файлcontent-product.phpза той самий період оновлювався десятки разів.
Чи можна використовувати is_admin() для захисту функцій кошика?
Ні, і це часта пастка. AJAX-запити WooCommerce (додавання в кошик, оновлення кількості) обробляються через admin-ajax.php, у цьому контексті is_admin() повертає true. Якщо ви обгорнете функції кошика в if ( ! is_admin() ), AJAX-оновлення фрагментів (add_to_cart_fragments) перестане працювати, і сума в іконці кошика не змінюватиметься без перезавантаження сторінки.
Огортати в
! is_admin()потрібно лише те, що не повинно виконуватися в адмінці (виведення HTML на фронті), але функції-обробники AJAX мають бути доступні завжди. Для коду з розділу 7 не ставтеis_admin()взагалі, WooCommerce сам викликає потрібні колбеки через свій AJAX-обробник, і обмеження зламає логіку.
Як додати підтримку WooCommerce у блокову тему (FSE)?
Для блокових тем декларація підтримки не змінилася, той самий add_theme_support('woocommerce'). Але замість хуків і перевизначення PHP-шаблонів ви працюєте в редакторі сайту: WooCommerce надає блоки (Products, Product Search, Cart, Checkout), які вставляються в шаблони через Appearance → Editor. Тонка кастомізація робиться через theme.json і CSS-змінні.
Блокові теми принципово змінюють підхід: ви не пишете PHP-хуки для верстки, а збираєте сторінки візуально з готових блоків WooCommerce. Але фундамент,
add_theme_supportуfunctions.php, залишається тим самим. А для тонких правок, які блоками не зробити (наприклад, кастомний текст на кнопці «У кошик»), старі добрі фільтри з цієї статті працюють і в FSE-темах.
Яку стратегію обрати під ваш проєкт
Якщо ви допрацьовуєте наявну тему, почніть із кроків 1 і 2: оголосіть підтримку та налаштуйте сітку. У більшості випадків цього достатньо, щоб магазин виглядав пристойно. Далі додавайте лише ті правки, які вирішують конкретну проблему: криву галерею, негарну пагінацію, відсутність кошика в меню.
Пишете тему з нуля для продажу чи розповсюдження, пройдіть увесь список. Кожен пункт додає користувачеві те, що він очікує від магазинної теми «з коробки»: керовану сітку, зум на товарах, живу іконку кошика. Код винесіть в inc/woocommerce.php і підвантажуйте за константою, тоді тема однаково добре працює і як блог, і як магазин.
Відправна точка завжди одна й та сама:
1 add_action( 'after_setup_theme', function() { 2 add_theme_support( 'woocommerce' ); 3 } );
Вісім рядків. Усе решта, деталі, які відрізняють тему «сумісну» від теми «заточеної».



