Диагностика задачи: зачем удалять товар из заказа после отмены или возврата
В стандартном WooCommerce товары, добавленные в заказ, сохраняются в базе даже если заказ отменён или возвращён. Это может приводить к ошибкам при статистике, инвентаризации и аналитике, особенно если товар в заказе больше не актуален. Автоматическое удаление таких товаров из отменённых или возвращённых заказов помогает держать данные в чистоте и предотвращает накладки.
Как определить, что товар в заказе нужно удалить
Товар нужно удалить, если статус заказа изменился на один из следующих:
cancelled— заказ отменён;refunded— заказ частично или полностью возвращён;failed— заказ неудачный (опционально, если нужно).
Удаление должно происходить только после подтверждения изменения статуса, чтобы не потерять данные преждевременно.
Пошаговое решение: код для автоматического удаления товаров из заказа
Реализуем на хуке woocommerce_order_status_changed. В обработчике проверяем новый статус и очищаем позиции заказа (items) при необходимости.
add_action('woocommerce_order_status_changed', 'wplessons_remove_items_on_cancel_refund', 20, 4);
function wplessons_remove_items_on_cancel_refund($order_id, $old_status, $new_status, $order) {
if (in_array($new_status, ['cancelled', 'refunded'])) {
// Получаем все позиции заказа
$items = $order->get_items();
foreach ($items as $item_id => $item) {
// Удаляем позицию из заказа
$order->remove_item($item_id);
}
// Сохраняем изменения
$order->calculate_totals();
$order->save();
}
}
Обратите внимание, что мы вызываем calculate_totals() для пересчёта итогов заказа после удаления позиций, и затем сохраняем заказ.
Альтернативный вариант: удалять только конкретные товары
Если нужно удалять не все товары, а только определённые (например, с конкретенным метаполем или товарной категорией), можно добавить фильтрацию:
foreach ($items as $item_id => $item) {
$product = $item->get_product();
if ($product && has_term('special-category', 'product_cat', $product->get_id())) {
$order->remove_item($item_id);
}
}
Проверка результата после внедрения кода
- Создайте тестовый заказ в WooCommerce с несколькими товарами.
- В админ-панели измените статус заказа на
cancelledилиrefunded. - Обновите страницу редактирования заказа и убедитесь, что список товаров пуст.
- Проверьте, что итоговые суммы заказа пересчитаны и равны нулю.
- Проверьте, что отчетность WooCommerce не учитывает удалённые товары в этих заказах.
Частые ошибки и как их исправлять
- Товары не удаляются: Убедитесь, что хук подключён с достаточным приоритетом (не ниже 20), и что функция получает правильный объект
$order. Также проверьте, что статус заказа действительно меняется наcancelledилиrefunded. - Итоговая сумма заказа не обновляется: Обязательно вызывайте
calculate_totals()иsave()после удаления позиций. - Ошибка при удалении: Иногда плагин кеширования или сторонние расширения блокируют изменение заказа. Попробуйте отключить их на время теста.
- Удаляются не все нужные товары: Проверьте логику фильтрации, если удаляете не все позиции.
Практические советы по безопасности и производительности
- Не удаляйте товары из заказов с другими статусами, чтобы избежать потери данных.
- Храните резервные копии базы данных перед внедрением кода, особенно если заказы важны для бухгалтерии.
- Если магазин большой и заказов много, оптимизируйте код, например, обрабатывайте удаление в асинхронных задачах WP Cron.
- Тестируйте решение на staging-сервере, чтобы избежать сбоев на живом сайте.
Сравнение вариантов реализации удаления товаров из заказа
| Метод | Плюсы | Минусы |
|---|---|---|
| Удаление всех товаров при смене статуса | Простая реализация, полное очищение заказа | Потеря данных по всем товарам, может не подходить для частичных возвратов |
| Удаление по категории или метаполю | Точный контроль, не удаляет все позиции | Сложнее в реализации, требует поддержки метаданных |
| Ручное удаление товаров в админке | Безопасно, контролируемо | Трудозатратно, можно забыть |