Диагностика проблемы: зачем запрещать удаление товаров после продажи
В WooCommerce администраторы и менеджеры магазина могут случайно удалить товары, которые уже были куплены клиентами. Это приводит к ошибкам в отчетах, нарушению работы заказов и плохому пользовательскому опыту, когда ссылки на купленные товары становятся нерабочими. Чтобы избежать подобных проблем, полезно запретить удаление товаров, у которых есть выполненные заказы.
Пошаговое решение: как запретить удалять товары с покупками
1. Проверка связей товара с заказами
Для начала нужно определить, есть ли у конкретного товара завершённые заказы. В WooCommerce для этого можно использовать класс WC_Order_Item_Product и запросы через WC_Order_Query.
2. Блокировка удаления товаров через хук WordPress
Основной способ запретить удаление поста (товара — тип записи product) — использовать хук before_delete_post. В нем проверим наличие покупок и отменим удаление при необходимости.
add_action('before_delete_post', function($post_id) {
// Проверяем, что это товар
if (get_post_type($post_id) !== 'product') {
return;
}
global $wpdb;
// Ищем заказы со статусом completed, processing, которые содержат этот товар
$order_ids = $wpdb->get_col($wpdb->prepare(
"SELECT DISTINCT order_id FROM {$wpdb->prefix}woocommerce_order_items woi
JOIN {$wpdb->prefix}woocommerce_order_itemmeta woim ON woi.order_item_id = woim.order_item_id
JOIN {$wpdb->prefix}posts p ON woi.order_id = p.ID
WHERE woim.meta_key = '_product_id' AND woim.meta_value = %d
AND p.post_type = 'shop_order'
AND p.post_status IN ('wc-completed', 'wc-processing')",
$post_id
));
if (!empty($order_ids)) {
// Отменяем удаление
wp_die('Удаление товара невозможно: товар уже был приобретён в заказах.');
}
});3. Предупреждение в админке при попытке удаления
Чтобы улучшить UX, можно добавить предупреждение в интерфейсе админки при попытке удалить такой товар через JavaScript, используя AJAX для проверки заказов. Ниже пример простейшей проверки при загрузке списка товаров.
add_action('admin_footer-edit.php', function() {
$screen = get_current_screen();
if ($screen->post_type !== 'product') return;
?>
<script>
jQuery(document).ready(function($){
$('.delete a').click(function(e){
var postId = $(this).closest('tr').attr('id').replace('post-', '');
var link = $(this);
e.preventDefault();
$.post(ajaxurl, {
action: 'check_product_orders',
product_id: postId
}, function(response){
if(response.hasOrders) {
alert('Удаление невозможно: товар уже был куплен.');
} else {
window.location = link.attr('href');
}
});
});
});
</script>
<?php
});
add_action('wp_ajax_check_product_orders', function() {
$product_id = intval($_POST['product_id']);
global $wpdb;
$order_ids = $wpdb->get_col($wpdb->prepare(
"SELECT DISTINCT order_id FROM {$wpdb->prefix}woocommerce_order_items woi
JOIN {$wpdb->prefix}woocommerce_order_itemmeta woim ON woi.order_item_id = woim.order_item_id
JOIN {$wpdb->prefix}posts p ON woi.order_id = p.ID
WHERE woim.meta_key = '_product_id' AND woim.meta_value = %d
AND p.post_type = 'shop_order'
AND p.post_status IN ('wc-completed', 'wc-processing')",
$product_id
));
wp_send_json(['hasOrders' => !empty($order_ids)]);
});Проверка результата после внедрения
- Попробуйте удалить товар с завершённым заказом — система должна блокировать удаление с сообщением.
- Если удалить товар без заказов — удаление должно пройти без ошибок.
- В списке товаров нажатие на ссылку удаления товара с заказами должно показывать предупреждение и отменять действие.
Частые ошибки и как их исправить
- Удаление не блокируется: Проверьте, что код подключён и что тип поста действительно
product. Возможно, код не загружается в админке. - Проблемы с запросом к базе: Убедитесь, что таблицы WooCommerce имеют стандартные префиксы, и используйте
$wpdb->prefixправильно. - Админ-скрипт не работает: Проверьте консоль браузера на ошибки JS, убедитесь, что jQuery загружен.
- Конфликты с другими плагинами: Отключите другие плагины, которые могут вмешиваться в удаление товаров.
Практические советы по безопасности и производительности
- Используйте кеширование результатов проверки заказов, если на сайте много товаров, чтобы уменьшить нагрузку на базу.
- Не показывайте детальные ошибки в
wp_dieна продакшене — лучше логировать и показывать общие сообщения. - Регулярно обновляйте WooCommerce и WordPress до последних версий, чтобы избежать уязвимостей и несовместимостей.
- Для улучшения UX рассмотрите интеграцию с плагинами типа Clearfy Pro (https://wpshop.ru/plugins/clearfy?utm_source=wp3.ru&utm_medium=article&utm_campaign=woocommerce-zapret-udaleniya-tovarov-posle-pokupki) для оптимизации и управления функционалом магазина.
Таблица сравнения способов блокировки удаления товара с покупками
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
Хук before_delete_post (PHP) | Запрет удаления на уровне сервера, блокирует процесс | Надёжно, невозможно обойти | Нет пользовательского предупреждения, только сообщение об ошибке |
| AJAX-проверка и JS-предупреждение | Показывает предупреждение в админке перед удалением | Улучшает UX, предупреждает заранее | Можно обойти через прямой запрос к базе или CLI |
| Плагин безопасности WooCommerce | Готовые решения с настройками | Простота установки | Может влиять на производительность, зависит от стороннего кода |