Каталог товаров WooCommerce: как настроить вывод, фильтры и категории

Каталог товаров WooCommerce: как настроить вывод, фильтры и категории

Кратко: каталог товаров WooCommerce — это архивная страница магазина, которая собирается из настроек кастомайзера (колонки и количество товаров на странице), цикла архива темы и таксономий product_cat / product_tag. Товары выводятся шорткодом [products], функцией wc_get_products() или WP_Query с tax_query; категории создаются в разделе «Товары → Категории» или через wp_insert_term(), а фильтры включаются виджетами WooCommerce («Фильтр по цене», «Фильтр по атрибуту») или собственным AJAX-обработчиком на admin-ajax.php. Ниже — рабочий код для каждого шага.

Как устроен каталог товаров WooCommerce

Каталог в WooCommerce — не отдельная страница, которую рисуют вручную, а архив товаров: специальный список записей типа product. WooCommerce при установке сам создаёт страницу «Магазин» и привязывает её к архиву в настройках «WooCommerce → Настройки → Товары» — поле «Страница магазина». Что бы вы ни набрали в редакторе этой страницы, при просмотре сайт покажет сетку товаров из цикла.

За наполнение каталога отвечают три таксономии:

  • product_cat — категории товаров (например, «Обувь», «Зимняя обувь»). Это главный инструмент структуры каталога;
  • product_tag — метки, более свободные подписи вроде «водостойкая» или «новинка 2026»;
  • pa_* — атрибуты (цвет, размер), которые заводятся в разделе «Товары → Атрибуты» и питают фильтры.

Внешний вид каталога собирают шаблоны темы: archive-product.php отвечает за страницу магазина и категорий, а карточку товара рисует content-product.php. Тема подключает эти файлы через хуки WooCommerce — поэтому большинство настроек делается фильтрами и экшенами, а не правкой плагина. Если вы только начинаете, вспомните, как устроены хуки WordPress: actions и filters, — в WooCommerce без них никуда.

Схема всегда одна: настройки определяют, сколько товаров показывать, шорткоды и запросы — какие именно товары выводить, виджеты и свой код — как их фильтровать. А если вы проектируете магазин с нуля, отталкивайтесь от материала о том, что учесть, когда заказываешь интернет-магазин на WordPress, — структура каталога закладывается ещё до установки WooCommerce.

Базовые настройки каталога: колонки и товары на странице

Откройте «Внешний вид → Настроить → WooCommerce → Каталог товаров». Здесь две ключевые настройки: количество колонок в сетке (по умолчанию 4) и сколько товаров показывать на одной странице каталога. Меняются мышкой, но работают только если тема поддерживает кастомайзер — у части тем сетка жёстко зашита в CSS.

Надёжный способ, не зависящий от темы, — фильтры. Добавьте код в functions.php дочерней темы:

add_filter( 'loop_shop_per_page', function ( $per_page ) {
    return 24; // товаров на странице каталога
}, 20 );

add_filter( 'loop_shop_columns', function () {
    return 3; // колонок в сетке каталога
} );

Фильтр loop_shop_per_page задаёт количество товаров на странице каталога, loop_shop_columns — число колонок. Сетка 24 товара в 3 колонки даёт восемь аккуратных рядов; на мобильных тема обычно перестраивает сетку сама, но проверьте это на телефоне.

Важная деталь: эти фильтры действуют только на архивах — странице «Магазин», категориях и метках. На сетки, выведенные шорткодом [products], они не влияют: там количество задаётся прямо в атрибутах шорткода. И не забывайте про кэш — после правки настроек сбрасывайте его, иначе увидите старую сетку. Как устроено кэширование WordPress и почему оно «прячет» изменения, мы разбирали отдельно.

Шорткод [products]: вывод товаров в любом месте

Шорткод [products] — самый быстрый способ показать товары там, где нет цикла магазина: на главной, в лендинге, в записи. Он пришёл на смену старым [recent_products], [sale_products] и [best_selling_products], которые ещё работают, но просто дублируют один и тот же вывод с разными сортировками.

[products limit="8" columns="4" category="obuv" orderby="popularity"]
[products limit="4" columns="4" on_sale="true"]
[products limit="12" columns="3" visibility="featured" paginate="true"]

Разбор атрибутов: limit — сколько товаров показать, columns — колонок в сетке, category — слаги категорий через запятую, orderby — сортировка (date, popularity, rating, price), on_sale="true" — только товары со скидкой, visibility="featured" — рекомендуемые, paginate="true" — пагинация внутри шорткода.

Три типовых сценария: новинки на главной — [products limit="8" orderby="date"]; блок «Скидки недели» — [products on_sale="true" limit="4"]; мини-каталог категории — [products category="obuv" limit="12"]. Шорткод вставляется в Gutenberg-блок «Шорткод», а если хотите оформить подборку по-своему — посмотрите, как создать свой блок Gutenberg, и оберните вывод товаров в собственную разметку.

Ограничение у шорткода одно: он рисует сетку «как есть» и почти не умеет фильтровать по произвольным полям. Для сложных выборок переходите к функциям.

Вывод каталога кодом: wc_get_products и WP_Query

wc_get_products — официальный способ

Функция wc_get_products() — рекомендованный WooCommerce интерфейс получения товаров. Она понимает специфичные аргументы (категория, тип товара, видимость) и корректнее работает с кэшем WooCommerce, чем «сырой» WP_Query:

$products = wc_get_products( [
    'limit'    => 12,
    'status'   => 'publish',
    'orderby'  => 'date',
    'order'    => 'DESC',
    'category' => [ 'obuv' ], // слаг категории
] );

foreach ( $products as $product ) {
    echo '<a href="' . get_permalink( $product->get_id() ) . '">';
    echo esc_html( $product->get_name() );
    echo ' — ' . wp_strip_all_tags( $product->get_price_html() );
    echo '</a>';
}

Функция возвращает массив объектов WC_Product — с ними удобно работать геттерами: get_name(), get_price(), get_image_id(). Кстати, товары WooCommerce доступны и через REST — это отдельный навык, о нём был гайд про REST API WordPress для новичков.

WP_Query с tax_query — для кастомных шаблонов

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

$paged = max( 1, get_query_var( 'paged' ) );

$q = new WP_Query( [
    'post_type'      => 'product',
    'post_status'    => 'publish',
    'posts_per_page' => 12,
    'paged'          => $paged,
    'tax_query'      => [
        [
            'taxonomy' => 'product_cat',
            'field'    => 'slug',
            'terms'    => 'obuv',
        ],
    ],
] );

if ( $q->have_posts() ) {
    woocommerce_product_loop_start();
    while ( $q->have_posts() ) {
        $q->the_post();
        wc_get_template_part( 'content', 'product' ); // стандартная карточка товара
    }
    woocommerce_product_loop_end();
    wp_reset_postdata();
}

Обратите внимание на woocommerce_product_loop_start() и woocommerce_product_loop_end(): они открывают и закрывают обёртку сетки с классами вашей темы, а wc_get_template_part( 'content', 'product' ) рисует стандартную карточку товара. Такой код кладут в отдельный файл и подключают через кастомный шаблон страницы WordPress — получается независимая страница каталога со своей структурой.

Сравнение способов вывода каталога

Четыре способа выше решают разные задачи. Чтобы не выбирать наугад, вот сравнение:

Способ Когда использовать Плюсы Минусы
Страница «Магазин» (архив) Основной каталог сайта Работает из коробки, есть пагинация и URL для SEO Кастомизация только через фильтры и шаблоны темы
Шорткод [products] Блоки «Новинки», «Скидки», подборки на лендингах Без кода, настраивается атрибутами Слабая фильтрация по произвольным полям
wc_get_products() Свои виджеты, блоки, выгрузки Официальный API, объекты WC_Product Нужно писать вывод и разметку самому
WP_Query + tax_query Кастомные страницы каталога, сложные условия Полный контроль: таксономии, поля, пагинация Легко ошибиться с пагинацией и сбросом запроса

Практика новичков проста: основной каталог оставьте архиву «Магазин», точечные подборки делайте шорткодом, а когда упрётесь в ограничения — переходите на wc_get_products() или WP_Query.

Категории товаров: создать и вывести

Категория через админку

Раздел «Товары → Категории» даёт всё необходимое: имя, слаг, описание, родительскую категорию и миниатюру, которая показывается в плитках категорий. Слаг пишите латиницей — он попадёт в URL страницы категории (/product-category/obuv/) и понадобится в шорткодах и tax_query.

Категория кодом

При миграции или автоматизации категории создают функцией wp_insert_term():

$new = wp_insert_term( 'Зимняя обувь', 'product_cat', [
    'slug'        => 'zimnyaya-obuv',
    'description' => 'Каталог зимней обуви: ботинки, сапоги, утеплённые модели.',
    'parent'      => 25, // ID родительской категории, 0 — верхний уровень
] );

if ( is_wp_error( $new ) ) {
    // чаще всего «term_exists» — категория с таким слагом уже есть
    error_log( 'Категория не создана: ' . $new->get_error_message() );
}

Функция вернёт массив с term_id созданной категории или объект ошибки — чаще всего «term_exists», если слаг занят. Запускайте такой код один раз (например, на after_switch_theme или из своего плагина-мигратора), а не на каждый просмотр страницы.

Вывод списка категорий

Список категорий каталога выводится функцией get_terms():

$cats = get_terms( [
    'taxonomy'   => 'product_cat',
    'hide_empty' => true,
    'parent'     => 0,
] );

if ( ! is_wp_error( $cats ) ) {
    foreach ( $cats as $cat ) {
        printf(
            '<a href="%s">%s (%d)</a>',
            esc_url( get_term_link( $cat ) ),
            esc_html( $cat->name ),
            (int) $cat->count
        );
    }
}

Быстрая альтернатива без кода — шорткод [product_categories number="8" columns="4" parent="0"]: он нарисует плитки категорий с миниатюрами (внутри работает функция woocommerce_subcategory_thumbnail()). Миниатюры категорий — те же картинки, что и у товаров, поэтому перед загрузкой сожмите их: мы писали про оптимизацию изображений в WordPress и формат WebP — каталог из двадцати плиток без сжатия тянет несколько мегабайт.

Стандартные фильтры WooCommerce: виджеты

Из коробки WooCommerce предлагает три виджета фильтрации: «Фильтр по цене» (ползунок), «Фильтр по атрибуту» (цвет, размер — любой активный атрибут товара) и «Фильтр по категории товаров». Кладутся в сайдбар каталога через «Внешний вид → Виджеты» и отображаются только на архивах: странице магазина, категории или метки.

Три нюанса, на которых спотыкаются новички:

  1. Виджеты фильтров не работают на статичных страницах. Если вы вывели каталог шорткодом на страницу «Каталог», фильтры там молча не появятся — им нужен настоящий архив с его URL-параметрами.
  2. Атрибут попадёт в фильтр, только если в «Товары → Атрибуты» у него включён показ на странице архива и хотя бы у одного товара заполнено значение.
  3. Фильтры применяются перезагрузкой страницы: каждая комбинация — новый запрос к серверу. Для крупного каталога это неудобно — переходим к AJAX.

AJAX-фильтрация каталога без перезагрузки

Собственный AJAX-фильтр — «джентльменский набор» интернет-магазина: покупатель щёлкает чекбоксы, сетка товаров перерисовывается на лету. Механика знакома по статье про AJAX в WordPress и admin-ajax.php: PHP-обработчик принимает условия, собирает WP_Query и возвращает готовый HTML сетки.

PHP-обработчик

// ajax-фильтр каталога: категория + максимальная цена
add_action( 'wp_ajax_ds_filter_products', 'ds_filter_products' );
add_action( 'wp_ajax_nopriv_ds_filter_products', 'ds_filter_products' );

function ds_filter_products() {
    check_ajax_referer( 'ds_filter', 'nonce' );

    $cat = sanitize_title( $_POST['category'] ?? '' );
    $max = absint( $_POST['max_price'] ?? 0 );

    $args = [
        'post_type'      => 'product',
        'post_status'    => 'publish',
        'posts_per_page' => 12,
    ];

    if ( $cat ) {
        $args['tax_query'] = [
            [
                'taxonomy' => 'product_cat',
                'field'    => 'slug',
                'terms'    => $cat,
            ],
        ];
    }

    if ( $max ) {
        $args['meta_query'] = [
            [
                'key'     => '_price',
                'value'   => $max,
                'compare' => '<=',
                'type'    => 'NUMERIC',
            ],
        ];
    }

    $q = new WP_Query( $args );

    ob_start();
    if ( $q->have_posts() ) {
        woocommerce_product_loop_start();
        while ( $q->have_posts() ) {
            $q->the_post();
            wc_get_template_part( 'content', 'product' );
        }
        woocommerce_product_loop_end();
    } else {
        echo '<p class="ds-no-products">Товары не найдены. Смягчите условия фильтра.</p>';
    }
    wp_reset_postdata();

    wp_send_json_success( [
        'html'  => ob_get_clean(),
        'found' => (int) $q->found_posts,
    ] );
}

Что здесь важно: check_ajax_referer() проверяет nonce и отсекает подделку запросов; sanitize_title() и absint() чистят входные данные; meta_query по ключу _price фильтрует по цене. Фильтр по цене через произвольное поле — самое медленное место больших каталогов (десятки тысяч товаров): если упрётесь в производительность, кэшируйте ответы или переходите на индексируемые таблицы.

Подключение скрипта и nonce

add_action( 'wp_enqueue_scripts', function () {
    wp_enqueue_script( 'ds-filter', get_stylesheet_directory_uri() . '/js/filter.js', [], '1.0', true );
    wp_localize_script( 'ds-filter', 'DS_FILTER', [
        'ajax_url' => admin_url( 'admin-ajax.php' ),
        'nonce'    => wp_create_nonce( 'ds_filter' ),
    ] );
} );

JavaScript фильтра

// форма фильтра: #ds-filters, контейнер каталога: .ds-catalog
document.addEventListener( 'change', function ( e ) {
    if ( ! e.target.matches( '.ds-filter' ) ) {
        return;
    }
    var form = document.getElementById( 'ds-filters' );
    var data = new FormData( form );
    data.append( 'action', 'ds_filter_products' );
    data.append( 'nonce', DS_FILTER.nonce );

    fetch( DS_FILTER.ajax_url, { method: 'POST', body: data } )
        .then( function ( r ) { return r.json(); } )
        .then( function ( res ) {
            if ( ! res.success ) {
                return;
            }
            document.querySelector( '.ds-catalog' ).innerHTML = res.data.html;
            document.querySelector( '.ds-found' ).textContent =
                'Найдено товаров: ' + res.data.found;
        } );
} );

Скрипт слушает событие change на элементах с классом .ds-filter, собирает форму целиком через FormData и подставляет ответ сервера в контейнер .ds-catalog. Счётчик .ds-found показывает покупателю, сколько товаров нашлось, — мелочь, которая снимает ощущение «фильтр завис».

Не экономьте на безопасности: nonce, санитизация и белые списки значений — стандарт, о котором напоминает гайд по безопасности WordPress для новичков. И ещё: AJAX-запросы к admin-ajax.php обычно исключают из кэша страниц — проверьте настройки своего плагина кэширования, чтобы фильтр не отдавал чужой закэшированный ответ.

Сортировка товаров в каталоге

По умолчанию WooCommerce сортирует каталог по menu_order — ручному порядку, который задаётся перетаскиванием товаров в списке «Товары → Все товары», — затем по популярности и новизне. Выпадающее меню «Сортировка» расширяется фильтрами: добавим свой вариант «По названию»:

// свой пункт в меню сортировки
add_filter( 'woocommerce_catalog_orderby', function ( $sortby ) {
    $sortby['alphabet'] = 'По названию (А–Я)';
    return $sortby;
} );

// обработка выбранного пункта
add_filter( 'woocommerce_get_catalog_ordering_args', function ( $args ) {
    if ( isset( $_GET['orderby'] ) && 'alphabet' === $_GET['orderby'] ) {
        $args['orderby'] = 'title';
        $args['order']   = 'ASC';
    }
    return $args;
} );

Здесь работают два фильтра в паре: woocommerce_catalog_orderby добавляет пункт в меню, woocommerce_get_catalog_ordering_args превращает выбор пользователя в аргументы запроса. По тому же шаблону добавляют сортировку «Сначала в наличии» (по _stock_status) или по произвольному полю. Значение $_GET['orderby'] сравнивайте с белым списком — как в примере, — а не подставляйте в запрос напрямую.

Если нужно поменять сортировку во всём каталоге принудительно (например, всегда «сначала дешевле»), тот же фильтр woocommerce_get_catalog_ordering_args без условий возвращает $args['orderby'] = 'meta_value_num' с $args['meta_key'] = '_price' — но подумайте дважды: покупатели привыкли управлять сортировкой сами.

А поля, по которым хочется нестандартно фильтровать и сортировать (артикул, бренд, размерная сетка), добавляются как метаполя — у нас есть гайд, как добавить свои поля оформления заказа в WooCommerce; для товаров механика через woocommerce_wp_text_input() очень похожа.

Как скрыть категорию или часть товаров из каталога

Классическая задача: служебные категории («Запчасти и сервис», «Комплектующие для монтажников») должны открываться по прямой ссылке для своих, но не мозолить глаза в общей витрине. Решение — фильтр основного запроса:

// прячем служебную категорию из витрины, но не с сайта
add_action( 'pre_get_posts', function ( $q ) {
    if ( is_admin() || ! $q->is_main_query() ) {
        return;
    }
    if ( ! $q->is_shop() && ! $q->is_product_category() ) {
        return;
    }

    $tax_query = $q->get( 'tax_query' ) ?: [];

    $tax_query[] = [
        'taxonomy' => 'product_cat',
        'field'    => 'slug',
        'terms'    => 'zapchasti-i-servis', // слаг служебной категории
        'operator' => 'NOT IN',
    ];

    $q->set( 'tax_query', $tax_query );
} );

Обратите внимание на два предохранителя: is_admin() не даёт фильтру влиять на админку, а проверка is_main_query() — на виджеты и вторичные циклы. Без них вы неожиданно «потеряете» товары в шорткодах и в списке товаров в админке.

Варианты без кода: у отдельного товара в блоке «Данные товара → Дополнительно» поставьте видимость в каталоге «Скрытый» — он исчезнет с витрины, но останется доступным по прямой ссылке. Из шорткода [product_categories] категорию исключают параметром exclude с ID термина. И пересматривайте скрытое регулярно: товары-призраки с выключенной видимостью всплывают в поиске, когда прямую ссылку расшарили в мессенджере — сюрпризы лучше не копить.

Типичные ошибки новичков при настройке каталога

  • 404 на странице категории. Чаще всего сломаны постоянные ссылки: пересохраните «Настройки → Постоянные ссылки» без изменений — правила перезапишутся, и категория откроется.
  • Витрина пустая, хотя товары есть. Проверьте видимость товаров (не «Скрытый») и слаг в tax_query: слаг пишется точно как в админке, латиницей, без пробелов.
  • Виджеты фильтров не появляются. Вы на статичной странице с шорткодом. Перенесите фильтры на архив магазина или соберите свой AJAX-фильтр из раздела 8.
  • Колонки не меняются. Тема задаёт сетку через CSS. Фильтр loop_shop_columns подскажет движку число колонок, но стили могут перебивать — правьте CSS дочерней темы.
  • Изменения не видны. Кэш страницы отдаёт старый каталог. Сбрасывайте кэш после каждой правки настроек или исключите страницы каталога из кэширования.
  • Дубли товаров. На одной странице работает и архив, и шорткод с теми же товарами — покупатель видит одну категорию дважды. Разводите подборки по категориям или убирайте дубль из основного цикла.

Частые вопросы о каталоге WooCommerce

Чем отличается страница «Магазин» от страницы категории?

Это один и тот же архив товаров с разными условиями: «Магазин» показывает все товары каталога, страница категории — только товары конкретной категории product_cat. Шаблон и виджеты у них общие, поэтому настройки колонок и фильтров действуют на обе страницы.

Можно ли вывести каталог товаров на обычной странице WordPress?

Можно — шорткодом [products] или своим шаблоном страницы с WP_Query. Но учтите: стандартные виджеты-фильтры на такой странице не работают, им нужен настоящий архив. Для страницы с шорткодом делайте AJAX-фильтр или ограничьтесь атрибутами самого шорткода.

Почему не отображается фильтр по атрибуту?

У атрибута выключено отображение на странице архива (галочка в «Товары → Атрибуты») либо ни у одного товара не заполнено значение этого атрибута. Фильтр показывает только те значения, которые реально встречаются у товаров текущей выборки.

Как поменять количество колонок, если настройка в кастомайзере не работает?

Добавьте фильтр loop_shop_columns в functions.php дочерней темы. Если сетка не изменилась и после этого — колонки жёстко заданы CSS темы: найдите класс обёртки ul.products и переопределите ширину карточек в стилях дочерней темы.

Как скрыть категорию из каталога, но оставить доступной по ссылке?

Для витрины — фильтр pre_get_posts с tax_query и оператором NOT IN (пример в разделе 10). Из меню и шорткода категорию исключают параметром exclude. Прямая ссылка /product-category/slug/ продолжит работать.

Нагружает ли AJAX-фильтр хостинг?

Каждый клик — это запрос к admin-ajax.php и WP_Query с meta_query по цене. На каталоге до нескольких тысяч товаров это незаметно; на больших — кэшируйте ответы фильтра или переносите цену в индексируемую структуру. Популярные выборки можно предрасчитывать через планировщик wp-cron.

TimeWeb

Вывод

Каталог WooCommerce собирается из простых деталей: архив «Магазин» с настройками колонок и лимита, шорткод [products] для подборок, wc_get_products() и WP_Query — когда нужен полный контроль, категории product_cat как каркас структуры, виджеты фильтров как минимум, AJAX-обработчик как максимум. Пройдите по порядку — базовые настройки, вывод, категории, фильтры, сортировка — и каталог будет работать предсказуемо, а каждая правка найдётся в одном месте: в дочерней теме.

Если проект перерос формат «сделать за вечер» — посмотрите услуги разработки интернет-магазинов и живые примеры внедрений в нашем портфолио; разборы WooCommerce, хуков и шаблонов регулярно выходят в блоге о разработке сайтов. Нужен совет по структуре каталога под вашу номенклатуру — напишите через форму контактов, поможем разложить товары по категориям и фильтрам.

Clearfy

Поделиться:
Telegram ВКонтакте