WooCommerce: Автоматическое изменение наличия товаров при изменении заказа

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

В WooCommerce стандартное поведение управления запасами происходит при оформлении заказа или вручную через админку. Однако при изменении заказа после его создания (например, администратор меняет количество товаров или добавляет/удаляет позиции) складские запасы не всегда обновляются корректно. Это приводит к рассинхронизации наличия и фактических остатков, что вызывает проблемы с продажами и учетными данными.

Основные признаки проблемы:

  • После изменения заказа вручную в админке складские запасы не корректируются;
  • В отчётах по запасам отображаются неверные значения;
  • Клиенты могут заказать товар с отрицательным запасом;
  • Автоматические уведомления о низком наличии не срабатывают вовремя.

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

1. Используем хуки WooCommerce для отслеживания изменений заказа

Для автоматического изменения наличия нужно отследить момент сохранения заказа и сравнить старые и новые данные по товарам. Для этого применим хук woocommerce_update_order и функцию для получения предыдущего состояния заказа.

add_action('woocommerce_update_order', 'custom_update_stock_on_order_change', 10, 1);

function custom_update_stock_on_order_change($order_id) {
    $order = wc_get_order($order_id);
    if (!$order) return;

    // Получаем старые данные заказа из базы
    $old_order = wc_get_order($order_id);
    $old_items = [];
    foreach ($old_order->get_items() as $item) {
        $old_items[$item->get_product_id()] = $item->get_quantity();
    }

    $new_items = [];
    foreach ($order->get_items() as $item) {
        $new_items[$item->get_product_id()] = $item->get_quantity();
    }

    // Сравниваем и обновляем запасы
    // ... (логика ниже)
}

2. Логика сравнения и корректировки запасов

Для каждого продукта в заказе вычисляем разницу между старым и новым количеством. Если количество увеличилось, уменьшаем склад; если уменьшилось — увеличиваем склад.

foreach ($new_items as $product_id => $new_qty) {
    $old_qty = isset($old_items[$product_id]) ? $old_items[$product_id] : 0;
    $diff = $new_qty - $old_qty;

    if ($diff !== 0) {
        $product = wc_get_product($product_id);
        if ($product && $product->managing_stock()) {
            $stock_qty = $product->get_stock_quantity();
            $new_stock = $stock_qty - $diff; // Уменьшаем или увеличиваем
            $product->set_stock_quantity($new_stock);
            $product->save();
        }
    }
}

// Обрабатываем удалённые товары
foreach ($old_items as $product_id => $old_qty) {
    if (!isset($new_items[$product_id])) {
        $product = wc_get_product($product_id);
        if ($product && $product->managing_stock()) {
            $stock_qty = $product->get_stock_quantity();
            $product->set_stock_quantity($stock_qty + $old_qty);
            $product->save();
        }
    }
}

3. Полный пример функции для functions.php

add_action('woocommerce_update_order', 'custom_update_stock_on_order_change', 10, 1);

function custom_update_stock_on_order_change($order_id) {
    $order = wc_get_order($order_id);
    if (!$order) return;

    // Получаем предыдущие данные из базы напрямую
    global $wpdb;
    $old_items = [];
    $results = $wpdb->get_results($wpdb->prepare(
        "SELECT product_id, qty FROM {$wpdb->prefix}woocommerce_order_itemmeta AS meta
         INNER JOIN {$wpdb->prefix}woocommerce_order_items AS items ON meta.order_item_id = items.order_item_id
         WHERE items.order_id = %d AND meta.meta_key = '_qty'",
         $order_id
    ));
    foreach ($results as $row) {
        $old_items[$row->product_id] = $row->qty;
    }

    $new_items = [];
    foreach ($order->get_items() as $item) {
        $new_items[$item->get_product_id()] = $item->get_quantity();
    }

    foreach ($new_items as $product_id => $new_qty) {
        $old_qty = isset($old_items[$product_id]) ? $old_items[$product_id] : 0;
        $diff = $new_qty - $old_qty;

        if ($diff !== 0) {
            $product = wc_get_product($product_id);
            if ($product && $product->managing_stock()) {
                $stock_qty = $product->get_stock_quantity();
                $new_stock = $stock_qty - $diff;
                $product->set_stock_quantity($new_stock);
                $product->save();
            }
        }
    }

    foreach ($old_items as $product_id => $old_qty) {
        if (!isset($new_items[$product_id])) {
            $product = wc_get_product($product_id);
            if ($product && $product->managing_stock()) {
                $stock_qty = $product->get_stock_quantity();
                $product->set_stock_quantity($stock_qty + $old_qty);
                $product->save();
            }
        }
    }
}

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

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

  • Создайте тестовый заказ с несколькими товарами, у которых включено управление запасами.
  • Подтвердите заказ и проверьте, что запасы уменьшились.
  • Отредактируйте заказ в админке: измените количество товаров, добавьте или удалите позицию.
  • Сохраните заказ и проверьте изменения запасов в карточках товаров.
  • Проверьте, что запасы не уходят в отрицательные значения без разрешения WooCommerce.

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

  • Запасы не изменяются после редактирования заказа: возможно, не подключен хук или функция не вызывается корректно. Проверьте, что код добавлен в functions.php или в плагин и не вызывает ошибок PHP.
  • Отрицательные значения запасов: проверьте настройки управления запасами в WooCommerce (Раздел Товары - Запасы). По умолчанию отрицательные запасы запрещены. Можно добавить проверку в коде, чтобы не уходить в минус.
  • Некорректное получение старых данных заказа: иногда данные в базе и объекте заказа могут не совпадать из-за кеширования. Используйте прямые запросы к базе для достоверности.
  • Производительность: при большом количестве товаров в заказе выполнение кода может замедлить сохранение. Оптимизируйте запросы и при необходимости делайте обновление асинхронно.

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

  • Используйте wc_get_product() и методы WooCommerce для работы с товарами, чтобы избежать прямого обновления таблиц без проверки.
  • Добавьте проверку прав пользователя, если код будет вызываться в админке, чтобы избежать несанкционированных изменений.
  • Обрабатывайте исключения и ошибки, чтобы не нарушить работу сайта при сбое в обновлении запасов.
  • При большом объёме заказов и товаров рассмотрите возможность кэширования данных и оптимизации SQL-запросов.
  • Для сложных сценариев используйте WP-Cron для отложенного обновления запасов без влияния на UX админ-панели.

Сравнение вариантов реализации

МетодПлюсыМинусы
Хук woocommerce_update_order с синхронным обновлениемПростота, мгновенное обновление запасовЗамедляет сохранение заказа при большом объёме данных
Отложенное обновление через WP-CronНе влияет на скорость админки, масштабируемостьЗадержка в обновлении запасов, сложность реализации
Использование сторонних плагинов управления запасамиГотовые решения, поддержка сложных сценариевСтоимость, избыточность, возможные конфликты
Автоматическое создание и удаление записей в WordPress по расписанию
15.09.2026
Автоматическое создание и удаление черновиков WordPress по расписанию
15.09.2026
WooCommerce: автоматическое отключение промо-кодов после успешного использования
16.08.2026
WooCommerce: Автоматическое отключение способов оплаты при неудачной оплате заказа
27.08.2026
WooCommerce: автоматическое отключение способов оплаты при неудачной оплате заказа
28.08.2026
×

AI-плагин

WPGPT
Сам создает статьи для вашего сайта WordPress

SEO и мета-теги

Парсинг конкурентов

Изображения

Комментарии

Подробнее