Диагностика задачи: зачем удалять товар после отмены заказа?
В стандартном WooCommerce отмена заказа не влияет на наличие товара в каталоге. Однако в некоторых бизнес-сценариях (например, при продаже уникальных или ограниченных товаров) необходимо автоматически удалять товар из базы данных сразу после отмены заказа, чтобы избежать повторных продаж. Это помогает автоматизировать управление каталогом и предотвращает ошибки с остатками.
Пошаговое решение: реализуем автоматическое удаление товара
1. Подключение к хуку отмены заказа
WooCommerce предоставляет хук woocommerce_order_status_cancelled, который срабатывает при смене статуса заказа на «отменён». Используем его для запуска удаления товара.
2. Получение товаров из заказа
В обработчике получаем все позиции заказа и извлекаем ID товаров.
3. Удаление товаров программно
Используем функцию wp_delete_post для удаления товаров вместе с их метаданными.
Пример кода:
add_action('woocommerce_order_status_cancelled', 'auto_delete_products_after_order_cancelled', 10, 1);
function auto_delete_products_after_order_cancelled( $order_id ) {
if ( ! $order_id ) return;
$order = wc_get_order( $order_id );
if ( ! $order ) return;
foreach ( $order->get_items() as $item ) {
$product_id = $item->get_product_id();
if ( $product_id ) {
// Проверяем, что продукт существует и не удалён
$product_post = get_post( $product_id );
if ( $product_post ) {
wp_delete_post( $product_id, true ); // true — принудительное удаление из корзины
}
}
}
}Проверка результата
- Создайте тестовый заказ с одним или несколькими товарами.
- Отмените заказ через админку WooCommerce.
- Проверьте, что товары, входившие в заказ, удалены из каталога.
- Если товары не удалены, проверьте логи ошибок сервера и включите WP_DEBUG для диагностики.
Частые ошибки и как их исправить
- Товары не удаляются: возможно, функция не подключена или хук не срабатывает. Проверьте правильность имени хука и приоритет.
- Удаляются не те товары: убедитесь, что вы используете
$item->get_product_id(), а не$item->get_variation_id()или другие ID. - Ошибки прав доступа: функция
wp_delete_postтребует прав администратора, убедитесь, что код запускается с нужной ролью. - Удаление приводит к ошибкам в других местах: если товары связаны с другими сущностями (например, связанные посты или отзывы), нужно продумать каскадное удаление.
Практические советы по безопасности и производительности
- Добавьте проверку nonce или используйте capability проверки, если код вызывается из пользовательских экранов.
- Перед удалением товара можно логировать ID для аудита и отката.
- Если товаров много, рассмотрите пакетное удаление с ограничением по времени, чтобы избежать таймаутов.
- Создайте резервные копии базы перед внедрением функции удаления.
Сравнение подходов удаления товара после отмены заказа
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
Удаление через хук woocommerce_order_status_cancelled |
Автоматическое удаление товара при смене статуса заказа на отменённый | Полная автоматизация, простота реализации | Риск удаления нужных товаров, если не фильтровать |
| Ручное удаление через админку | Администратор сам удаляет товары после отмены заказа | Контроль над удалением, меньше риска ошибок | Большая ручная работа, риск забыть удалить |
| Использование плагина управления состоянием товара | Отложенное или условное скрытие/удаление товаров | Гибкость, можно настроить логику под бизнес | Может потребоваться покупка/настройка плагина |
Дополнительный пример: удаление только уникальных товаров
Если нужно удалять не все товары из заказа, а только уникальные (например, с мета-полем _unique_item), добавьте проверку:
add_action('woocommerce_order_status_cancelled', 'auto_delete_unique_products_after_order_cancelled', 10, 1);
function auto_delete_unique_products_after_order_cancelled( $order_id ) {
if ( ! $order_id ) return;
$order = wc_get_order( $order_id );
if ( ! $order ) return;
foreach ( $order->get_items() as $item ) {
$product_id = $item->get_product_id();
if ( $product_id ) {
$is_unique = get_post_meta( $product_id, '_unique_item', true );
if ( $is_unique ) {
wp_delete_post( $product_id, true );
}
}
}
}