В чем суть задачи: автоматическое обновление наличия товаров на складе
В стандартном WooCommerce изменение количества товаров в уже созданном заказе не всегда корректно отражается на остатках товаров на складе. Особенно это актуально для магазинов с управлением запасами, где администратор вручную корректирует заказ (добавляет или уменьшает количество позиций) после оформления. Без дополнительной логики складские остатки могут не обновляться, приводя к рассинхронизации и ошибкам при дальнейших заказах.
Диагностика проблемы: как проверить, что остатки не обновляются
- Откройте любой сделанный заказ в админке WooCommerce.
- Измените количество товара в заказе (например, увеличьте на 1).
- Сохраните заказ и проверьте в разделе «Товары» остаток на складе по этому товару.
- Если остаток не изменился, значит автоматическое обновление не происходит.
Также можно проверить логи WooCommerce или включить WP_DEBUG для выявления возможных ошибок при сохранении заказа.
Почему WooCommerce не обновляет остатки при редактировании заказов
По умолчанию WooCommerce обновляет склад при создании заказа и при смене статуса заказа (например, на «завершен»), но не отслеживает изменения позиций и количества в уже существующих заказах. Для автоматического обновления нужно самостоятельно добавить логику, которая будет:
- Определять разницу в количестве товара между старым и новым значением.
- Корректировать остаток на складе с учетом этой разницы.
Пошаговое решение: добавляем автоматическое изменение остатков при изменении заказа
1. Отслеживаем изменение заказа в админке
Для этого используем хук woocommerce_saved_order_items, который вызывается после сохранения позиций заказа.
2. Сохраняем текущие количества товаров в заказе перед изменениями
Чтобы вычислить разницу, нужно знать старые значения. Воспользуемся get_items() и сохраним данные в transient перед редактированием.
3. Вычисляем разницу и обновляем складские запасы
Сравниваем старые и новые количества и сдвигаем остаток на складе.
Пример кода для functions.php темы или плагина
<?php
// Сохраняем текущие количества товаров при загрузке страницы редактирования заказа
add_action('load-post.php', function() {
global $post;
if (get_post_type($post) === 'shop_order') {
$order = wc_get_order($post->ID);
$items = $order->get_items();
$quantities = [];
foreach ($items as $item) {
$quantities[$item->get_id()] = $item->get_quantity();
}
set_transient('order_item_quantities_' . $post->ID, $quantities, 3600); // храним 1 час
}
});
// После сохранения позиций заказа корректируем остатки
add_action('woocommerce_saved_order_items', function($order_id) {
$order = wc_get_order($order_id);
if (!$order) return;
$old_quantities = get_transient('order_item_quantities_' . $order_id);
if (!$old_quantities) return;
$items = $order->get_items();
foreach ($items as $item) {
$item_id = $item->get_id();
$new_qty = $item->get_quantity();
$old_qty = isset($old_quantities[$item_id]) ? $old_quantities[$item_id] : 0;
$difference = $new_qty - $old_qty;
if ($difference !== 0) {
$product = $item->get_product();
if ($product && $product->managing_stock()) {
$stock_qty = $product->get_stock_quantity();
$product->set_stock_quantity($stock_qty - $difference);
$product->save();
}
}
}
delete_transient('order_item_quantities_' . $order_id);
});
?>Проверка результата после внедрения
- Откройте заказ в админке WooCommerce.
- Измените количество товара в заказе (увеличьте или уменьшите).
- Сохраните заказ и обновите страницу товара в разделе «Товары».
- Проверьте, что изменился остаток на складе на соответствующее количество.
Частые ошибки и их исправление
- Не сохраняются транзиенты: убедитесь, что у вас работает механизм transient API (например, не отключен кеш в базе данных).
- Функция не вызывается: проверьте, что код подключен и нет синтаксических ошибок.
- Обновление остатков не происходит: проверьте, что товар управляет запасами (
$product->managing_stock()возвращает true). - Изменение остатков идет в неправильную сторону: перепроверьте вычисление разницы (
$difference = $new_qty - $old_qty;), возможно логика инвертирована.
Практические советы по безопасности и производительности
- Не храните большие массивы данных в transient без срока жизни, чтобы не засорять базу.
- Проверяйте права пользователя при изменении заказа, чтобы избежать несанкционированных изменений остатков.
- Добавьте логирование изменений остатков для последующего аудита.
- Для магазинов с большим количеством заказов рассмотрите возможность реализации фоновой очереди обновлений остатков для снижения нагрузки.
Сравнение вариантов решения
| Метод | Преимущества | Недостатки |
|---|---|---|
Код из примера (хук woocommerce_saved_order_items) | Полный контроль, без сторонних плагинов, гибкость | Требует тестирования, ручная поддержка |
| Сторонние плагины управления складом | Готовые решения, поддержка, интерфейс | Может быть дорого, избыточно для задачи, нагрузка |
| Ручное обновление остатков | Простота, минимальные изменения | Риск ошибок, рассинхронизация |