WooCommerce: как автоматически удалять товары с нулевым количеством из корзины по атрибутам

Диагностика проблемы: почему в корзине остаются товары с нулевым запасом

При работе с WooCommerce иногда возникает ситуация, когда в корзине пользователя остаются товары, которых нет в наличии (запас равен 0). Это создает неудобства — клиенты пытаются оформить заказ, но потом получают ошибку на этапе оплаты. Особенно актуально, если нужно удалять товары с нулевым запасом по определённым атрибутам, например, цвет или размер.

Проверить проблему можно так:

  • Добавьте в корзину товар с нулевым количеством на складе;
  • Перейдите в корзину и убедитесь, что товар там отображается;
  • Попробуйте оформить заказ — WooCommerce может показать ошибку или не дать оформить заказ.

Если такие товары в корзине есть, значит, механизм проверки запасов либо отключён, либо работает не полностью.

Пошаговое решение: удаление товаров с нулевым запасом по атрибутам из корзины

1. Фильтрация товаров в корзине по запасу и атрибутам

Реализуем хук woocommerce_before_calculate_totals, который проверит каждый товар в корзине и удалит его, если количество на складе равно 0 и он соответствует заданным атрибутам.

add_action('woocommerce_before_calculate_totals', 'remove_zero_stock_products_from_cart', 10, 1);
function remove_zero_stock_products_from_cart( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;

    // Атрибуты для фильтрации (пример: цвет = красный)
    $target_attributes = [
        'pa_color' => 'red',   // 'pa_' + slug атрибута, значение в нижнем регистре
        'pa_size' => 'large'
    ];

    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $product = $cart_item['data'];

        // Проверяем запас
        if ( !$product->is_in_stock() || $product->get_stock_quantity() === 0 ) {
            // Проверяем атрибуты вариативного товара
            $remove = true;
            if ( $product->is_type('variation') ) {
                $variation_attrs = $product->get_variation_attributes();
                foreach ( $target_attributes as $attr_name => $attr_value ) {
                    if ( !isset($variation_attrs[$attr_name]) || strtolower($variation_attrs[$attr_name]) !== strtolower($attr_value) ) {
                        $remove = false;
                        break;
                    }
                }
            } else {
                // Для простых товаров проверяем атрибуты товара
                foreach ( $target_attributes as $attr_name => $attr_value ) {
                    $product_attrs = $product->get_attributes();
                    if ( !isset($product_attrs[$attr_name]) ) {
                        $remove = false;
                        break;
                    }
                    $options = $product_attrs[$attr_name]->get_options();
                    $options_lower = array_map('strtolower', $options);
                    if ( !in_array(strtolower($attr_value), $options_lower) ) {
                        $remove = false;
                        break;
                    }
                }
            }

            if ( $remove ) {
                $cart->remove_cart_item($cart_item_key);
            }
        }
    }
}

2. Добавление уведомления пользователю

Чтобы клиент понимал, почему товар пропал из корзины, добавим уведомление:

add_action('woocommerce_cart_updated', 'notify_user_removed_zero_stock_products');
function notify_user_removed_zero_stock_products() {
    if ( isset( WC()->session ) ) {
        $removed = WC()->session->get('removed_zero_stock', false);
        if ( $removed ) {
            wc_print_notice( __('Некоторые товары с нулевым запасом и выбранными атрибутами были удалены из корзины.'), 'notice' );
            WC()->session->set('removed_zero_stock', false);
        }
    }
}

// Модифицируем функцию удаления, чтобы ставить флаг
add_action('woocommerce_before_calculate_totals', 'remove_zero_stock_products_from_cart_and_flag', 9, 1);
function remove_zero_stock_products_from_cart_and_flag( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;

    $target_attributes = [
        'pa_color' => 'red',
        'pa_size' => 'large'
    ];

    $removed_any = false;
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $product = $cart_item['data'];

        if ( !$product->is_in_stock() || $product->get_stock_quantity() === 0 ) {
            $remove = true;
            if ( $product->is_type('variation') ) {
                $variation_attrs = $product->get_variation_attributes();
                foreach ( $target_attributes as $attr_name => $attr_value ) {
                    if ( !isset($variation_attrs[$attr_name]) || strtolower($variation_attrs[$attr_name]) !== strtolower($attr_value) ) {
                        $remove = false;
                        break;
                    }
                }
            } else {
                foreach ( $target_attributes as $attr_name => $attr_value ) {
                    $product_attrs = $product->get_attributes();
                    if ( !isset($product_attrs[$attr_name]) ) {
                        $remove = false;
                        break;
                    }
                    $options = $product_attrs[$attr_name]->get_options();
                    $options_lower = array_map('strtolower', $options);
                    if ( !in_array(strtolower($attr_value), $options_lower) ) {
                        $remove = false;
                        break;
                    }
                }
            }

            if ( $remove ) {
                $cart->remove_cart_item($cart_item_key);
                $removed_any = true;
            }
        }
    }

    if ( $removed_any && isset( WC()->session ) ) {
        WC()->session->set('removed_zero_stock', true);
    }
}

Как проверить, что решение работает

  • Добавьте в WooCommerce товар с атрибутами color=red и запасом 0;
  • Поместите этот товар в корзину;
  • Обновите страницу корзины — товар должен исчезнуть;
  • Появится уведомление о том, что товар удалён из-за отсутствия запаса;
  • Проверьте, что товары с другими цветами или атрибутами остаются в корзине.

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

  • Неправильный slug атрибута. В WooCommerce атрибуты называются с префиксом pa_. Например, цвет — это pa_color. Проверьте правильность написания и регистр.
  • Проверка запаса для вариативных товаров. Метод get_stock_quantity() возвращает запас вариации, а не родительского продукта.
  • Отсутствие уведомления. Если уведомление не появляется, убедитесь, что сессии работают корректно и тема выводит уведомления WooCommerce.
  • Проблемы с AJAX корзиной. Если корзина обновляется через AJAX, убедитесь, что скрипты и хуки корректно обрабатываются.

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

  • Хук woocommerce_before_calculate_totals вызывается часто, поэтому код должен быть оптимизирован и не выполнять лишних операций.
  • Кэширование результатов проверки атрибутов в массиве поможет избежать повторного вычисления.
  • Не используйте прямые запросы к базе данных — все операции должны идти через API WooCommerce.
  • Проверяйте, что пользовательская сессия доступна, чтобы безопасно устанавливать флаги уведомлений.

Сравнение подходов: плагин vs кастомный код

ПодходПлюсыМинусыКомпромисс
Плагин (например, WooCommerce Stock Manager)Простота установки, готовый функционалИзбыточный функционал, нагрузка, ограниченная кастомизацияХорошо для новичков и стандартных задач
Кастомный код (представленный выше)Точная настройка под задачу, высокая производительностьТребует навыков разработки и тестированияИдеально для проектов с уникальными требованиями
Как использовать методы владельцев WordPress для управления публикациями
24.11.2025
Как добавить динамические таблицы в WordPress с помощью плагинов и кода
04.02.2026
WooCommerce: Исключение товаров по цвету и размеру из корзины
20.04.2026
Оптимизация базы данных WordPress: практические советы
06.11.2025
Как создать автоматический импорт данных из Excel в WordPress
18.12.2025

Возникли задачи по WP? Вы можете задать свой вопрос на FAQwp.com Либо обратиться к специалистам поддержки.