WooCommerce: автоматическое отключение товаров при отсутствии на складе с подъемом запасов

Диагностика проблемы с отображением товаров в WooCommerce при нулевых остатках

В стандартной установке WooCommerce товары с нулевым остатком могут оставаться активными и видимыми в каталоге, что вводит покупателей в заблуждение. Часто владельцы магазинов хотят автоматически скрывать или отключать такие товары, чтобы не принимать заказы на отсутствие. Однако при последующем пополнении запасов товар должен автоматически становиться доступным для продажи. В этой статье разберем, как реализовать эту логику программно.

Как WooCommerce работает с остатками товаров

WooCommerce хранит количество на складе в метаполе _stock и флаг управления запасами _manage_stock. При активации управления запасами WooCommerce автоматически меняет статус товара на «В наличии» или «Нет в наличии», но не всегда скрывает товар из каталога.

По умолчанию товары с нулевым запасом отображаются, если не включена опция «Скрывать товары без наличия» в настройках WooCommerce.

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

1. Проверка и настройка WooCommerce

  • В админке WordPress перейдите в WooCommerce > Настройки > Товары > Запасы.
  • Убедитесь, что включена опция Включить управление запасами.
  • Активируйте Скрывать товары без наличия, чтобы товары с нулевым остатком автоматически не отображались в каталоге.

Однако данный метод не отключает товар, а только скрывает. Для полного отключения нужно программное решение.

2. Добавление кода для автоматического изменения статуса товара

Используем хук woocommerce_product_set_stock, который срабатывает при изменении запасов товара.

add_action('woocommerce_product_set_stock', function($product) {
    if (!$product->managing_stock()) {
        return; // Управление запасами отключено
    }

    $stock_quantity = $product->get_stock_quantity();
    $post_id = $product->get_id();

    // Проверяем остаток
    if ($stock_quantity <= 0) {
        // Отключаем товар (переводим в черновик)
        if (get_post_status($post_id) !== 'draft') {
            wp_update_post([
                'ID' => $post_id,
                'post_status' => 'draft'
            ]);
        }
    } else {
        // Включаем товар (делаем опубликованным)
        if (get_post_status($post_id) !== 'publish') {
            wp_update_post([
                'ID' => $post_id,
                'post_status' => 'publish'
            ]);
        }
    }
});

Этот код автоматически переводит товар в статус черновика при нулевом или отрицательном остатке и возвращает в публикацию при наличии товара на складе.

3. Обработка вариативных товаров

Для вариативных товаров нужно учитывать остатки вариаций. Если у всех вариаций запас равен 0, отключаем родительский товар.

add_action('woocommerce_variation_set_stock', function($variation) {
    $parent_id = $variation->get_parent_id();
    $parent = wc_get_product($parent_id);
    
    if (!$parent) return;

    $children = $parent->get_children();
    $all_out_of_stock = true;

    foreach ($children as $child_id) {
        $child = wc_get_product($child_id);
        if ($child && $child->get_stock_quantity() > 0) {
            $all_out_of_stock = false;
            break;
        }
    }

    if ($all_out_of_stock) {
        if (get_post_status($parent_id) !== 'draft') {
            wp_update_post(['ID' => $parent_id, 'post_status' => 'draft']);
        }
    } else {
        if (get_post_status($parent_id) !== 'publish') {
            wp_update_post(['ID' => $parent_id, 'post_status' => 'publish']);
        }
    }
});

Проверка результата после внедрения

  • Измените остаток товара через админку WooCommerce или через API.
  • Проверьте, что при обнулении остатка товар становится черновиком и не отображается в каталоге.
  • При увеличении остатка товар возвращается к опубликованному состоянию и виден покупателям.
  • Для вариативных товаров проверьте, что статус родительского товара меняется в зависимости от остатков вариаций.

Для быстрой проверки можно использовать WP-CLI:

wp post list --post_type=product --post_status=draft,publish --fields=ID,post_title,post_status

Частые ошибки и их исправление

  • Код не срабатывает при изменении остатков: Проверьте, что управление запасами включено и используемые хуки совпадают с версией WooCommerce.
  • Товар не меняет статус: Возможно, другой плагин блокирует изменение статуса. Проверьте логи ошибок и конфликтующие хуки.
  • Вариативные товары не обрабатываются корректно: Убедитесь, что подхватываете изменения запасов вариаций, а не только родительского товара.
  • Статус товара меняется, но он все равно отображается в каталоге: Проверьте настройки видимости и кэш сайта (например, плагинов кеширования).

Практические советы по безопасности и производительности

  • Добавляйте код в дочернюю тему или собственный плагин, чтобы избежать потери при обновлениях.
  • Используйте функцию wp_update_post аккуратно, чтобы не создавать рекурсию — в нашем случае хук срабатывает на изменение запаса, а мы меняем статус поста, что не вызывает повторного срабатывания.
  • Отключите кеширование страниц с динамическим контентом (например, страницы каталога и карточки товара) либо используйте AJAX-запросы для обновления статуса товара.
  • Для больших магазинов с тысячами товаров рассмотрите отложенное обновление статусов через WP Cron или внешние скрипты, чтобы избежать нагрузки на сервер.
  • Следите за логами ошибок PHP для выявления возможных проблем при обновлении статусов.

Сравнение вариантов реализации отключения товаров по складу

МетодПреимуществаНедостаткиРекомендации
Опция WooCommerce «Скрывать товары без наличия»Простота настройки, не требует кодаТовар остается опубликованным, возможна путаница с заказамиПодходит для небольших магазинов
Код с изменением статуса постаПолное отключение товара, гибкостьТребует технических знаний, возможны конфликты с плагинамиЛучше для средних и больших проектов
Плагины для управления видимостью товаровДополнительные функции, GUIЗависимость от стороннего кода, ценаЕсли нужен расширенный контроль без программирования
⭐⭐⭐⭐⭐