Диагностика проблемы: почему в корзине остаются товары с нулевым запасом
При работе с 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) | Простота установки, готовый функционал | Избыточный функционал, нагрузка, ограниченная кастомизация | Хорошо для новичков и стандартных задач |
| Кастомный код (представленный выше) | Точная настройка под задачу, высокая производительность | Требует навыков разработки и тестирования | Идеально для проектов с уникальными требованиями |