Кратко: каталог товаров 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 предлагает три виджета фильтрации: «Фильтр по цене» (ползунок), «Фильтр по атрибуту» (цвет, размер — любой активный атрибут товара) и «Фильтр по категории товаров». Кладутся в сайдбар каталога через «Внешний вид → Виджеты» и отображаются только на архивах: странице магазина, категории или метки.
Три нюанса, на которых спотыкаются новички:
- Виджеты фильтров не работают на статичных страницах. Если вы вывели каталог шорткодом на страницу «Каталог», фильтры там молча не появятся — им нужен настоящий архив с его URL-параметрами.
- Атрибут попадёт в фильтр, только если в «Товары → Атрибуты» у него включён показ на странице архива и хотя бы у одного товара заполнено значение.
- Фильтры применяются перезагрузкой страницы: каждая комбинация — новый запрос к серверу. Для крупного каталога это неудобно — переходим к 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.

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



