Диагностика проблемы: зачем запрещать удаление купленных товаров
В стандартной установке WooCommerce администратор может удалять товары в любой момент. Однако если товар уже куплен, удаление может привести к потере данных о заказах, некорректной статистике и проблемам с юридической отчетностью. Особенно актуально для цифровых товаров и подписок. Необходимо реализовать запрет на удаление товара, если он был частью хотя бы одного завершённого заказа.
Как отследить, что товар был куплен
Нужно проверить наличие завершённых заказов, содержащих данный товар. Для этого используется класс WC_Order_Query и функции WooCommerce для получения заказов по статусу и содержимому.
function has_product_been_purchased( $product_id ) {
$args = [
'limit' => 1,
'status' => ['completed', 'processing', 'on-hold'],
'return' => 'ids',
'meta_query' => [],
];
$orders = wc_get_orders( $args );
foreach ( $orders as $order_id ) {
$order = wc_get_order( $order_id );
foreach ( $order->get_items() as $item ) {
if ( $item->get_product_id() == $product_id ) {
return true;
}
}
}
return false;
}Пошаговое решение: запрет удаления товара в админке WooCommerce
Для решения задачи нужно добавить проверку при попытке удаления товара через хук before_delete_post. Если товар был куплен, отменить удаление с сообщением об ошибке.
add_action( 'before_delete_post', 'prevent_deleting_purchased_product' );
function prevent_deleting_purchased_product( $post_id ) {
if ( get_post_type( $post_id ) !== 'product' ) {
return;
}
if ( has_product_been_purchased( $post_id ) ) {
wp_die( 'Удаление товара невозможно: товар уже был куплен в одном из заказов.' );
}
}Если нужно запретить удаление массово (bulk delete), можно использовать bulk_actions-edit-product для удаления опции или обработать handle_bulk_actions-edit-product, но базовый хук before_delete_post защитит от удаления через любой способ.
Проверка результата после внедрения
- Попробуйте удалить товар, который не был куплен — удаление должно пройти успешно.
- Попробуйте удалить товар, который был куплен в хотя бы одном заказе — появится ошибка, и товар останется в базе.
- Проверьте через бэкенд, что данные заказа сохраняются и статистика не нарушена.
Частые ошибки и как их исправить
- Ошибка: Удаление товара срабатывает без предупреждения.
Причина: Хукbefore_delete_postне подключён или код находится не в функции темы/плагина.
Исправление: Убедитесь, что код подключён через файл плагина или functions.php активной темы. - Ошибка: Проверка не обнаруживает купленные товары.
Причина: Неправильные статусы заказа или кэширование.
Исправление: Проверьте статусы заказа и попробуйте добавить логи для отладки, напримерerror_log().
Практические советы по производительности и безопасности
- Функция
has_product_been_purchased()может быть ресурсоёмкой на больших базах. Кешируйте результат с помощью Transients API:
function has_product_been_purchased( $product_id ) {
$cache_key = 'product_purchased_' . $product_id;
$cached = get_transient( $cache_key );
if ( $cached !== false ) {
return $cached;
}
$args = [
'limit' => 1,
'status' => ['completed', 'processing', 'on-hold'],
];
$orders = wc_get_orders( $args );
foreach ( $orders as $order ) {
foreach ( $order->get_items() as $item ) {
if ( $item->get_product_id() == $product_id ) {
set_transient( $cache_key, true, DAY_IN_SECONDS );
return true;
}
}
}
set_transient( $cache_key, false, DAY_IN_SECONDS );
return false;
}- Для улучшения безопасности используйте проверку прав пользователя перед удалением товаров, например, проверяйте
current_user_can('delete_product', $post_id). - Регулярно очищайте транзиенты или обновляйте кеш при изменении заказов.
Сравнение подходов: плагин vs кастомный код
| Подход | Преимущества | Недостатки |
|---|---|---|
| Кастомный код (хуки WordPress + WooCommerce) | Полный контроль, лёгкость интеграции, без лишних зависимостей | Требует навыков PHP, ответственность за поддержку |
| Плагин для защиты товаров | Быстрая установка, готовые функции | Может быть избыточным, не всегда адаптирован под нужды проекта |