Ситуация типовая: товар закончился, но продолжает висеть в каталоге, попадать в поиск и собирать клики в карточку, где покупатель видит сообщение о недоступности. Для магазина это лишний шум в аналитике и лишние вопросы в поддержку. Если задача именно в том, чтобы скрыть товары с нулевым остатком, а не просто отключить покупку, лучше решать её на уровне WooCommerce-запросов и карточки товара, а не вручную прятать позиции в админке.
Ниже — рабочий вариант без выдуманных хуков и без привязки к сторонним плагинам. Он подходит, если у вас включён учёт склада в WooCommerce и товары помечаются как отсутствующие на складе.
Когда проблема действительно в нулевых остатках
Сначала проверьте, что именно происходит у вас. Иногда товар «пропадает» не из-за остатка, а из-за фильтров темы, кэша или настроек видимости.
- Товар имеет статус
outofstock, но всё ещё отображается в архиве товаров. - Поиск WordPress находит карточку, хотя покупать её нельзя.
- Категории показывают старые позиции после обновления остатков.
- В карточке товара есть кнопка покупки, но при добавлении в корзину WooCommerce блокирует заказ.
Что проверить в админке WooCommerce
Откройте WooCommerce → Настройки → Товары → Запасы и убедитесь, что включён учёт запасов. Дальше проверьте сам товар: в блоке данных товара должен быть указан остаток, а статус склада — В наличии или Нет в наличии. Если учёт запасов выключен, код ниже не даст ожидаемого результата, потому что WooCommerce не будет считать товар отсутствующим по складу.
Пошаговое решение: скрываем товары с нулевым остатком
Логика простая: исключаем товары со статусом outofstock из основных витринных запросов и отдельно убираем их из поиска. Это не ломает карточку товара напрямую, но делает так, чтобы покупатель не попадал на недоступные позиции из каталога.
Добавьте код в functions.php дочерней темы или в собственный мини-плагин. Второй вариант надёжнее: код не потеряется при смене темы.
add_action( 'woocommerce_product_query', 'wp_lessons_hide_outofstock_products' );
function wp_lessons_hide_outofstock_products( $q ) {
if ( is_admin() ) {
return;
}
$meta_query = (array) $q->get( 'meta_query' );
$meta_query[] = array(
'key' => '_stock_status',
'value' => 'outofstock',
'compare' => '!='
);
$q->set( 'meta_query', $meta_query );
}
add_action( 'pre_get_posts', 'wp_lessons_hide_outofstock_from_search' );
function wp_lessons_hide_outofstock_from_search( $query ) {
if ( is_admin() || ! $query->is_main_query() || ! $query->is_search() ) {
return;
}
$post_type = $query->get( 'post_type' );
if ( empty( $post_type ) ) {
$query->set( 'post_type', 'product' );
}
$meta_query = (array) $query->get( 'meta_query' );
$meta_query[] = array(
'key' => '_stock_status',
'value' => 'outofstock',
'compare' => '!='
);
$query->set( 'meta_query', $meta_query );
}Этот вариант работает в большинстве стандартных сценариев, но у него есть важная оговорка: он влияет на запросы витрины и поиска, а не на все возможные места вывода товаров. Если тема или плагин строит собственный запрос, его может понадобиться донастроить отдельно.
Если нужно скрывать товар полностью, а не только из каталога
Иногда задача жёстче: товар должен исчезать не только из архива и поиска, но и из связанных товаров, рекомендаций и блоков WooCommerce. В таком случае удобнее использовать фильтр видимости товара. WooCommerce умеет хранить видимость через таксономию product_visibility, и это более корректный путь, чем пытаться вручную править каждый шаблон.
add_action( 'woocommerce_product_set_stock_status', 'wp_lessons_sync_visibility_for_outofstock', 10, 3 );
function wp_lessons_sync_visibility_for_outofstock( $product_id, $stock_status, $product ) {
if ( 'outofstock' === $stock_status ) {
wp_set_object_terms( $product_id, 'exclude-from-catalog', 'product_visibility', true );
wp_set_object_terms( $product_id, 'exclude-from-search', 'product_visibility', true );
} else {
wp_remove_object_terms( $product_id, 'exclude-from-catalog', 'product_visibility' );
wp_remove_object_terms( $product_id, 'exclude-from-search', 'product_visibility' );
}
}Здесь есть нюанс: не все магазины хотят автоматически менять видимость при каждом изменении склада. Если у вас есть товары под заказ или предзаказ, такой подход может скрыть то, что должно оставаться доступным. В этом случае лучше ограничиться только витриной и поиском.
Сравнение подходов
| Подход | Что делает | Плюсы | Минусы |
|---|---|---|---|
| Настройки WooCommerce | Ручное скрытие товара в админке | Без кода, быстро | Не масштабируется, легко забыть обновить статус |
| Фильтр запросов | Убирает outofstock из каталога и поиска | Гибко, не трогает карточку товара | Нужно проверить тему и кэш |
| Изменение видимости | Скрывает товар шире по витрине | Подходит для жёсткого сценария | Может затронуть предзаказы и связанные товары |
Как проверить, что решение сработало
После внедрения не ограничивайтесь визуальной проверкой главной страницы. Нужны несколько точек контроля.
- Откройте категорию, где есть товар с нулевым остатком, и убедитесь, что он не отображается.
- Проверьте поиск по названию товара: карточка не должна появляться в результатах.
- Если товар уже был в кеше, очистите кэш страницы и объектный кэш, если он используется.
- Откройте саму карточку товара по прямой ссылке: она может оставаться доступной, если вы не скрывали её полностью.
- Проверьте связанные товары и блоки рекомендаций на странице товара.
Для быстрой диагностики полезно временно вывести значение мета-поля _stock_status у проблемного товара через get_post_meta() или посмотреть его в базе. Если там не outofstock, код выше просто не сработает, и причину нужно искать в синхронизации склада.
Частые ошибки и как их исправить
Товар не исчезает из каталога
Чаще всего причина в кэше или в том, что тема строит собственный запрос без стандартного woocommerce_product_query. Сначала очистите кэш, потом проверьте, не переопределяет ли тема шаблоны архива товаров.
Товар пропал, хотя должен быть доступен под заказ
Значит, вы слишком агрессивно скрываете всё, что не в наличии. Для товаров под заказ лучше не использовать автоматическое исключение из каталога, а показывать отдельный статус наличия и отключать только кнопку покупки.
Поиск WordPress всё ещё находит карточку
Некоторые темы используют не стандартный поиск WooCommerce, а собственный AJAX-поиск. Тогда нужен отдельный фильтр именно для этого поиска. Универсального решения без знания конкретного плагина тут нет.
После обновления склада товар не возвращается в каталог
Это бывает, если вы добавили только скрытие, но не сделали обратное снятие термов видимости. В таком случае товар остаётся исключённым даже после появления остатка. Проверьте, что код обрабатывает оба состояния.
Безопасность и производительность
Если товаров много, не стоит каждый раз делать тяжёлые запросы к базе на фронтенде. Используйте стандартные хуки WooCommerce, а не ручной перебор всех товаров на каждой странице. Код выше работает через модификацию запроса и не сканирует каталог целиком.
Ещё один практический момент: если вы часто меняете остатки через импорт, проверьте, как обновляется поле _stock_status. При кривом импорте можно получить ситуацию, когда остаток уже нулевой, а статус всё ещё instock. Тогда скрытие не сработает, потому что проблема не в витрине, а в данных.
Если вам нужно не только скрытие, но и чистка дублей, лишних мета-данных и мусора в магазине, иногда удобнее закрыть часть таких задач отдельным инструментом вроде Clearfy Pro, но саму логику скрытия товаров с нулевым остатком всё равно лучше держать в коде и проверять на своём сценарии.