
🔧 Jak przygotować motyw WordPress do WooCommerce: pełny przewodnik dla deweloperów
Pisze Pan/Pani własny motyw i chce w nim umieścić sklep? Technicznie WooCommerce działa z każdym motywem, to tylko wtyczka. Ale „działa" nie znaczy „wygląda jak trzeba": rozjeżdża się siatka produktów, rozjeżdżają się sidebary, standardowe style wchodzą w konflikt z Pana/Pani stylami.
Problem jest głębszy niż kilka reguł CSS. Od wersji WooCommerce 3.3 motyw bez zadeklarowanego wsparcia otrzymuje uproszczone renderowanie przez shortkody oraz ostrzeżenia w panelu administracyjnym. Traci Pan/Pani pełną kontrolę nad układem.
Poniżej gotowe snippety: od deklaracji wsparcia po aktywny koszyk w menu. Każdy został sprawdzony na aktualnej wersji WooCommerce i podzielony na sekcje, od fundamentów po precyzyjne dostrajanie.
💡 Szybki przegląd:
- Najpierw motyw musi jawnie zadeklarować wsparcie dla WooCommerce, bez tego nie włączą się nadpisania szablonów i część funkcji
- Kod proszę umieszczać w osobnym pliku (na przykład
inc/woocommerce.php), który jest ładowany tylko przy aktywnej wtyczce - Konfiguracja siatki sklepu wymaga dwóch filtrów: jeden zmienia kolumny, drugi dodaje klasę do
body - Galeria produktów, zoom, lightbox i slider włączane są osobnymi wywołaniami
add_theme_support - Koszyk w menu powinien aktualizować się przez AJAX, proszę użyć filtra
add_to_cart_fragments
1. Fundament: deklaracja wsparcia i sprawdzanie aktywności
Pierwsza i najważniejsza rzecz: motyw musi jawnie powiedzieć WooCommerce: „wspieram Cię". Bez tego wtyczka nie aktywuje nadpisań szablonów i wyświetla ostrzeżenia w panelu administracyjnym. Od WooCommerce 3.3 motyw bez zadeklarowanego wsparcia otrzymuje uproszczone renderowanie przez shortkody, to działa, ale ogranicza kontrolę nad układem.
1 add_action( 'after_setup_theme', function() { 2 add_theme_support( 'woocommerce' ); 3 } );
Ważne, aby używać właśnie hooka after_setup_theme, a nie init, tak zaleca dokumentacja WooCommerce. Od wersji 3.3+ można od razu przekazać ustawienia siatki:
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 } );
Te parametry ustawiają wartości domyślne dla customizera (WooCommerce → Obrazy produktów / Katalog produktów) i zwalniają użytkownika z konieczności ręcznego konfigurowania siatki.
Sprawdzanie aktywności wtyczki
Kiedy oddaje Pan/Pani motyw do dystrybucji, nie można po prostu wrzucić snippetów WooCommerce na koniec functions.php, ich wywołanie spowoduje błąd krytyczny, jeśli wtyczka nie jest aktywna. Kod powinien być ładowany tylko przy działającym 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 }
Stała jest obliczana raz, a następnie w dowolnym miejscu motywu może Pan/Pani opakować wywołanie w if ( MYTHEME_WOOCOMMERCE_ACTIVE ). To czystsze rozwiązanie niż każdorazowe wywoływanie class_exists lub is_plugin_active.
2. Zarządzanie stylami WooCommerce
WooCommerce dostarcza trzy pliki CSS: woocommerce-general, woocommerce-layout i woocommerce-smallscreen. Idealnie nie usuwa się ich, tylko nadpisuje w swoim motywie, wtedy zewnętrzne rozszerzenia WooCommerce, które opierają się na tych klasach, nie psują się. Ale jeśli pisze Pan/Pani wszystko od zera i chce pełnej kontroli, oto jak je usunąć.
Usunięcie wszystkich stylów naraz:
1 add_filter( 'woocommerce_enqueue_styles', '__return_empty_array' );
Lub usunięcie selektywne:
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' );
W praktyce częściej stosuje się drugi wariant: usuwa się woocommerce-layout (siatka procentowa), ale zostawia woocommerce-general (przyciski, komunikaty, formularze) i punktowo nadpisuje je własnym CSS-em z wyższym priorytetem.
3. Konfiguracja stron sklepu
Ile produktów pokazywać
Filtr loop_shop_per_page kontroluje liczbę produktów na stronie sklepu i w archiwach (kategorie, tagi):
1 function mytheme_woo_posts_per_page( $cols ) { 2 return 12; 3 } 4 add_filter( 'loop_shop_per_page', 'mytheme_woo_posts_per_page' );
Liczba kolumn w siatce
Tutaj potrzebne są dwa filtry. Sam loop_shop_columns nie wystarczy: w przeciwieństwie do shortkodów WooCommerce (które mają opakowanie z klasą columns-N), na stronach sklepu takiej klasy nie ma. Dlatego dodajemy ją do 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' );
Teraz w CSS można pisać selektory .columns-4 ul.products li.product i będą one stosowane właśnie do siatki sklepu.
Nagłówek sklepu
WooCommerce domyślnie wyświetla „Shop" jako nagłówek na stronie sklepu. Jeśli Pana/Pani motyw już potrafi pokazywać nagłówki archiwów, ten duplikat przeszkadza:
1 add_filter( 'woocommerce_show_page_title', '__return_false' );
Jeśli natomiast używa Pan/Pani the_archive_title(), można podmienić nagłówek na nazwę strony sklepu (ustawianą w panelu administracyjnym):
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. Galeria produktów: zoom, lightbox i slider
Od wersji WooCommerce 3.0 pojawiła się nowa galeria produktów oparta na FlexSlider, PhotoSwipe i jQuery Zoom. W wersjach 3.0-3.2 jest ona domyślnie wyłączona i wymaga jawnego włączenia. Począwszy od 3.3 galeria jest włączona dla motywów nie-WooCommerce i wyłączona dla motywów, które zadeklarowały wsparcie; włącza Pan/Pani potrzebne komponenty samodzielnie:
1 add_theme_support( 'wc-product-gallery-slider' ); 2 add_theme_support( 'wc-product-gallery-zoom' ); 3 add_theme_support( 'wc-product-gallery-lightbox' );
Można włączyć tylko część: na przykład slider i zoom, a lightbox zastąpić własnym rozwiązaniem z Fancybox. Każda dyrektywa ładuje swoje skrypty, dlatego zbędnych lepiej nie włączać.
Liczba kolumn w miniaturach galerii (pod głównym obrazem produktu):
1 function mytheme_woo_product_thumbnails_columns() { 2 return 4; 3 } 4 add_action( 'woocommerce_product_thumbnails_columns', 'mytheme_woo_product_thumbnails_columns' );
5. Produkty powiązane i up-selling (cross-sells / up-sells)
Na stronie produktu WooCommerce wyświetla bloki „Produkty powiązane" (related) oraz „Z tym kupują również" (up-sells). Ich liczba i siatka są konfigurowane osobno.
Ile produktów powiązanych pokazywać:
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' );
Kolumny dla bloków up-sells i related: ta sama historia co z siatką sklepu: zmieniamy zarówno kolumny, jak i klasę na 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' );
Proszę zwrócić uwagę: w woocommerce_output_related_products_args są dwa filtry z różnymi priorytetami, mytheme_woo_related_posts_per_page (domyślnie 10) zmienia posts_per_page, a mytheme_woo_related_columns (priorytet 10) zmienia columns. Nie kolidują one ze sobą, ponieważ działają na różnych kluczach tej samej tablicy $args.
6. Paginacja i znaczek wyprzedaży
Strzałki paginacji sklepu można zastąpić ikonami Pana/Pani motywu:
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' );
Zamiast Font Awesome proszę wstawić własne klasy ikon lub bezpośrednio SVG.
Tekst na plakietce wyprzedaży (Sale!) można łatwo nadpisać, co jest wygodne w przypadku witryn w innym języku lub po prostu aby usunąć wykrzyknik:
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' );
Dla języka polskiego proszę zastąpić 'Sale' przez 'Скидка', tłumaczenie zostanie pobrane automatycznie, jeśli mają Państwo pliki MO WooCommerce w języku polskim.
7. Dynamiczny koszyk w menu
Prawdopodobnie najbardziej pożądany element w każdym szablonie sklepowym: ikona koszyka w nawigacji z aktualną kwotą. Implementacja składa się z trzech części: dodania elementu do menu, wygenerowania HTML koszyka oraz aktualizacji 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' );
Krytycznie ważny moment: proszę nie opakowywać tych funkcji w is_admin(). Zapytania AJAX koszyka przychodzą przez admin-ajax.php i jeśli funkcja jest niedostępna w kontekście administracyjnym, aktualizacja ceny w menu po prostu nie zadziała. theme_location proszę zastąpić identyfikatorem swojego menu (w przykładzie primary).
8. Alternatywne podejście: szablon woocommerce.php
Opisane wyżej hooki to najbardziej elastyczna i najbezpieczniejsza z punktu widzenia aktualizacji metoda. Jeśli jednak potrzebują Państwo radykalnie przekroić całą obudowę sklepu i stron produktowych, istnieje droga przez osobny szablon.
Proszę utworzyć w katalogu głównym motywu plik woocommerce.php (kopię page.php) i zastąpić główną pętlę wywołaniem 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
Ta metoda jest prostsza, ale ma swoją cenę: jeden szablon dla wszystkich stron WooCommerce, zarówno sklepu, kategorii, jak i karty produktu. Dokładne dostosowanie (inną siatkę, inny pasek boczny na różnych stronach) jest trudniejsze. Proszę wybierać ją tylko wtedy, gdy bieżący motyw zupełnie nie współpracuje z WooCommerce na poziomie znaczników i są Państwo gotowi zaakceptować te ograniczenia.
⁉️🤔 Często zadawane pytania
Czy usuwanie domyślnych stylów WooCommerce jest obowiązkowe?
Nie jest obowiązkowe. Bezpieczniejszą ścieżką jest pozostawienie ich i nadpisywanie selektorów we własnym motywie z wyższym priorytetem. W ten sposób zachowują Państwo zgodność z rozszerzeniami, które opierają się na standardowych klasach WooCommerce. Całkowite usunięcie (
__return_empty_array) jest uzasadnione tylko wtedy, gdy piszą Państwo motyw sklepowy od zera i mają pewność, że żadne zewnętrzne wtyczki nie będą dodawać elementów stylizowanych pod WooCommerce. W większości przypadków wystarczy selektywnie wyłączyćwoocommerce-layout(procentowa siatka koliduje z flexboksami i gridami nowoczesnych motywów), awoocommerce-generaliwoocommerce-smallscreenpozostawić i starannie nadbić przez kaskadę CSS, w ten sposób otrzymują Państwo czystą siatkę bez utraty kompatybilności.
Dlaczego zmiana liczby kolumn w sklepie nie działa?
Ponieważ sam filtr loop_shop_columns nie wystarcza. WooCommerce używa klas .columns-N na opakowaniu do działania siatki, a są one automatycznie dodawane tylko do shortkodów ([products columns="4"]). Na stronach sklepu i archiwów tego opakowania nie ma, klasę należy przypisać do body przez body_class. Dwa filtry z sekcji 3 całkowicie rozwiązują problem.
Filtr
loop_shop_columnszmienia zmienną PHP, którą WooCommerce przekazuje do szablonu, ale siatka CSS jest powiązana z klasą opakowania. Bez klasycolumns-4nabodyPaństwa styleul.products li.productnie mają selektora kontekstu i albo nie są stosowane, albo uderzają we wszystkie listy produktów na stronie.
Czy trzeba przebudowywać motyw po aktualizacji WooCommerce?
Jeśli używają Państwo hooków (wszystkie snippety z tego artykułu), nie. Hooki zmieniają się niezwykle rzadko. Jeśli nadpisują Państwo szablony (pliki z woocommerce/templates/), tak, należy porównywać swoje kopie z aktualnymi po każdej dużej aktualizacji. Właśnie dlatego oficjalna dokumentacja zaleca hooki jako lepszą metodę dostosowywania.
Hooki to kontrakt. WooCommerce gwarantuje ich stabilność między wersjami. Szablony to implementacja, która może zmienić się w każdej chwili: zostaną dodane nowe akcje, zmieni się znacznik, zmienią się nazwy klas. Przez pięć lat istnienia hooków
loop_shop_columnsiwoocommerce_output_related_products_argsich sygnatura nie zmieniła się ani razu, podczas gdy plikcontent-product.phpbył w tym samym okresie aktualizowany dziesiątki razy.
Czy można użyć is_admin() do ochrony funkcji koszyka?
Nie i jest to częsta pułapka. Żądania AJAX WooCommerce (dodawanie do koszyka, aktualizacja ilości) są obsługiwane przez admin-ajax.php, w tym kontekście is_admin() zwraca true. Jeśli opakują Państwo funkcje koszyka w if ( ! is_admin() ), aktualizacja fragmentów AJAX (add_to_cart_fragments) przestanie działać, a suma w ikonie koszyka nie będzie się zmieniać bez przeładowania strony.
W
! is_admin()należy opakowywać tylko to, co nie powinno być wykonywane w panelu administracyjnym (wyświetlanie HTML na froncie), ale funkcje obsługi AJAX muszą być dostępne zawsze. Dla kodu z sekcji 7 proszę w ogóle nie stosowaćis_admin(), WooCommerce sam wywołuje potrzebne callbacki przez swój handler AJAX, a ograniczenie złamie logikę.
Jak dodać wsparcie WooCommerce w motywie blokowym (FSE)?
Dla motywów blokowych deklaracja wsparcia nie uległa zmianie, to samo add_theme_support('woocommerce'). Jednak zamiast hooków i nadpisywania szablonów PHP pracują Państwo w edytorze witryny: WooCommerce udostępnia bloki (Products, Product Search, Cart, Checkout), które wstawia się do szablonów przez Appearance → Editor. Subtelną personalizację wykonuje się przez theme.json i zmienne CSS.
Motywy blokowe zasadniczo zmieniają podejście: nie piszą Państwo hooków PHP do układu, lecz składają strony wizualnie z gotowych bloków WooCommerce. Ale fundament,
add_theme_supportwfunctions.php, pozostaje ten sam. A do subtelnych poprawek, których nie da się zrobić blokami (np. niestandardowy tekst na przycisku „Do koszyka"), stare dobre filtry z tego artykułu działają również w motywach FSE.
Jaką strategię wybrać do swojego projektu
Jeśli ulepszają Państwo istniejący motyw, proszę zacząć od kroków 1 i 2: zadeklarować wsparcie i skonfigurować siatkę. W większości przypadków to wystarczy, aby sklep wyglądał przyzwoicie. Następnie proszę dodawać tylko te poprawki, które rozwiązują konkretny problem: krzywą galerię, nieładną paginację, brak koszyka w menu.
Jeśli piszą Państwo motyw od zera na sprzedaż lub do dystrybucji, proszę przejść całą listę. Każdy punkt dodaje użytkownikowi to, czego oczekuje od motywu sklepowego „od razu po instalacji": sterowalną siatkę, zoom na produktach, aktywną ikonę koszyka. Kod proszę wynieść do inc/woocommerce.php i ładować warunkowo na podstawie stałej, wtedy motyw działa równie dobrze zarówno jako blog, jak i sklep.
Punkt wyjścia jest zawsze ten sam:
1 add_action( 'after_setup_theme', function() { 2 add_theme_support( 'woocommerce' ); 3 } );
Osiem linijek. Cała reszta to detale, które odróżniają motyw „kompatybilny" od motywu „zoptymalizowanego".



