Как отключить отложенные товары в корзине WooCommerce при изменении остатков
Сценарий типичный для магазина с живым складом: клиент добавил товар в корзину, потом остаток изменился, а на checkout товар уже недоступен или доступен не в том количестве. В результате появляются ошибки оформления, лишние возвраты к корзине и вопросы в поддержку. Если у вас включено управление запасами в WooCommerce, это можно обработать без тяжелых костылей — на этапе обновления корзины и перед оформлением заказа.
Когда проблема действительно возникает
Чаще всего это видно в магазинах с синхронизацией из 1С, МойСклад, ERP или просто при ручном изменении остатков администратором. WooCommerce не всегда мгновенно «вычищает» корзину у уже зашедшего пользователя: товар может остаться в сессии, хотя на складе его уже нет. Если не вмешаться, покупатель увидит ошибку только на checkout.
Признаки, что дело именно в корзине, а не в оплате
- товар лежит в корзине, но при переходе к оформлению появляется сообщение о недоступности;
- количество в корзине больше, чем доступно на складе;
- после обновления страницы корзина не меняется, хотя остатки уже обновились;
- ошибка появляется только у части пользователей, а не у всех.
Диагностика: что проверить до правки кода
Сначала убедитесь, что WooCommerce действительно управляет остатками у нужных товаров. Откройте карточку товара и проверьте, включены ли опции учета запасов и ограничения по количеству. Если остатки ведутся внешней системой, важно понять, как часто они синхронизируются и кто источник истины: WooCommerce или ERP.
Дальше проверьте, не мешает ли кэш. Если у вас есть кэш страниц, корзина и checkout должны быть исключены из кэширования. Иначе вы можете лечить не ту проблему: товар не исчезает не из-за склада, а из-за старого HTML.
Полезно посмотреть, как WooCommerce ведет себя без кастомного кода: добавьте товар в корзину, затем в админке уменьшите остаток до нуля и обновите корзину в браузере. Если товар остается до следующего шага, значит нужна серверная проверка на стороне корзины.
Рабочий подход: проверять остаток при загрузке корзины и перед checkout
Самый надежный вариант — не ждать ошибки на оплате, а удалить недоступные позиции из корзины сразу после ее инициализации и повторно проверить перед оформлением заказа. Так пользователь видит проблему раньше и может заменить товар без лишних действий.
Ниже пример для functions.php дочерней темы или небольшого mu-plugin. Код проходит по корзине, проверяет остаток у каждого товара и удаляет позицию, если товара больше нет в наличии или доступного количества не хватает.
<?php
add_action( 'woocommerce_before_calculate_totals', 'wpbono_remove_unavailable_cart_items', 20 );
add_action( 'woocommerce_check_cart_items', 'wpbono_remove_unavailable_cart_items' );
function wpbono_remove_unavailable_cart_items() {
if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
return;
}
$cart = WC()->cart;
$removed = false;
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
if ( ! $product || ! is_a( $product, 'WC_Product' ) ) {
continue;
}
if ( ! $product->managing_stock() ) {
continue;
}
$stock_quantity = $product->get_stock_quantity();
$in_cart_qty = (int) $cart_item['quantity'];
if ( $product->is_in_stock() === false || ( is_numeric( $stock_quantity ) && $in_cart_qty > (int) $stock_quantity ) ) {
$cart->remove_cart_item( $cart_item_key );
$removed = true;
}
}
if ( $removed && ! is_admin() ) {
wc_add_notice( __( 'Некоторые товары были удалены из корзины, потому что их остаток изменился.', 'woocommerce' ), 'notice' );
}
}Этот вариант простой, но у него есть важная оговорка: woocommerce_before_calculate_totals может вызываться несколько раз за запрос. Поэтому не стоит внутри него делать тяжелые запросы к внешнему API или сложную логику синхронизации. Для проверки уже загруженных данных WooCommerce этого достаточно.
Если остатки приходят из внешней системы
Когда склад живет не в WooCommerce, а в другой системе, лучше не пытаться «угадывать» остаток из карточки товара. Надежнее хранить актуальное значение в мета-поле и обновлять его по крону или по webhook. Тогда корзина будет проверять уже локальное число, а не делать запрос в ERP на каждом открытии страницы.
Если у вас есть собственная синхронизация, полезно обновлять не только _stock, но и статус наличия. Иначе товар может числиться как доступный, хотя фактически его уже нет.
<?php
// Пример: ручное обновление остатка у товара.
$product_id = 123;
$new_stock = 0;
$product = wc_get_product( $product_id );
if ( $product ) {
$product->set_manage_stock( true );
$product->set_stock_quantity( $new_stock );
$product->set_stock_status( $new_stock > 0 ? 'instock' : 'outofstock' );
$product->save();
}Сравнение подходов: плагин, код или только настройки
| Подход | Что решает | Минус |
|---|---|---|
| Только настройки WooCommerce | Базовый учет остатков | Не убирает товар из уже созданной корзины |
| Код в теме или mu-plugin | Удаление недоступных позиций до checkout | Нужна аккуратная проверка и тестирование |
| Плагин синхронизации склада | Автоматическое обновление данных из внешней системы | Зависимость от стороннего решения и его логики |
Как проверить, что решение сработало
Проверка должна быть не «на глаз», а по сценарию. Сначала добавьте товар в корзину, затем в админке уменьшите остаток до нуля или ниже количества в корзине. После этого обновите корзину и перейдите к checkout. Если код работает, товар исчезнет из корзины или WooCommerce покажет уведомление до оформления заказа.
- товар удаляется из корзины после обновления страницы;
- на checkout не появляется ошибка о недоступности этого же товара;
- сообщение в корзине объясняет, что произошло;
- итоговая сумма пересчитывается без ручного вмешательства.
Если у вас включен лог ошибок, проверьте, что в нем нет предупреждений о пустом объекте товара или о вызове метода у несуществующего объекта. Это особенно важно на магазинах с вариативными товарами и нестандартными плагинами доставки.
Частые ошибки и как их исправить
Проверяют только is_in_stock()
Этого недостаточно, если товар в наличии, но количество в корзине больше доступного остатка. Нужно смотреть и на get_stock_quantity(), и на количество в корзине.
Ставят код в родительскую тему
После обновления темы правка исчезает. Для такой логики лучше использовать дочернюю тему или отдельный mu-plugin.
Не исключают checkout из кэша
Если checkout отдается из кэша, пользователь может видеть старую корзину и старые сообщения. Исключите корзину, checkout и страницу «Мой аккаунт» из кэширования на уровне плагина или сервера.
Проверяют остаток в каждом запросе к внешнему API
Это быстро превращается в узкое место. Если склад внешний, сначала синхронизируйте данные в WooCommerce, а уже потом проверяйте локальный остаток.
Что еще стоит учесть для производительности и безопасности
Не делайте удаление товаров из корзины «тихим», если это влияет на сумму заказа. Пользователь должен понимать, почему корзина изменилась. Иначе вы получите лишние обращения в поддержку и недоверие к оформлению заказа.
Если логика сложная и затрагивает несколько сценариев — например, разные склады, вариации и предзаказ — лучше вынести ее в отдельный мини-плагин. Так проще отключить правку для диагностики и не потерять ее при смене темы.
Для магазинов, где важна чистота фронтенда и отсутствие лишних дублей в шаблонах, полезно дополнительно проверить настройки SEO и технической оптимизации. Если нужен инструмент для чистки лишнего кода и системных дублей, можно посмотреть Clearfy Pro: https://wpshop.ru/plugins/clearfy?utm_source=wpbono.ru&utm_medium=article&utm_campaign=woocommerce-otklyuchit-otkladannye-tovary-v-korzine-pri-izmenenii-sklada
Если после внедрения логики корзина ведет себя нестабильно, сначала отключите кастомный код и повторите тест. Так вы быстро поймете, проблема в вашей проверке остатка или в стороннем плагине, который тоже меняет содержимое корзины.