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

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

В WooCommerce стандартно отсутствует ограничение на удаление товаров из админки, вне зависимости от того, были ли они проданы. Это может привести к потере данных о продажах, нарушению отчетности и проблемам с налоговой документацией. Особенно важно для магазинов с большим объемом заказов сохранить историю проданных товаров.

Пошаговое решение: запрет удаления товаров с заказами в WooCommerce

1. Проверка, был ли товар продан

Для начала нужно написать функцию, которая проверит, есть ли у товара завершённые заказы. Проверка будет происходить по статусу заказов completed или processing.

function has_product_sales($product_id) {
    global $wpdb;
    $query = $wpdb->prepare(
        "SELECT COUNT(*) FROM {$wpdb->prefix}woocommerce_order_items AS order_items
         
         INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id
         
         INNER JOIN {$wpdb->prefix}posts AS posts ON order_items.order_id = posts.ID
         
         WHERE posts.post_type = 'shop_order'
         AND posts.post_status IN ('wc-completed','wc-processing')
         AND itemmeta.meta_key = '_product_id'
         AND itemmeta.meta_value = %d",
        $product_id
    );
    $count = $wpdb->get_var($query);
    return $count > 0;
}

2. Запрет удаления товара через фильтр WordPress

Используем хук user_has_cap, чтобы снять право удаления товара, если он был продан.

add_filter('user_has_cap', function($allcaps, $caps, $args, $user) {
    if (isset($args[0]) && in_array($args[0], ['delete_post', 'delete_product'])) {
        $post_id = $args[2];
        $post_type = get_post_type($post_id);
        if ($post_type === 'product' && has_product_sales($post_id)) {
            $allcaps['delete_post'] = false;
            $allcaps['delete_product'] = false;
        }
    }
    return $allcaps;
}, 10, 4);

3. Блокировка удаления через Ajax и Bulk Actions

WooCommerce и WordPress позволяют удалять товары через массовые действия и AJAX-запросы. Для надежной защиты добавим проверку на уровне pre_delete_post.

add_action('pre_delete_post', function($post_id) {
    if (get_post_type($post_id) === 'product' && has_product_sales($post_id)) {
        wp_die('Удаление товара, который был продан, запрещено.');
    }
});

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

  • Попробуйте удалить товар, который не имел продаж — удаление должно пройти.
  • Попробуйте удалить товар, который продавался — должно появиться сообщение об ошибке и удаление не произойдет.
  • Проверьте массовое удаление (Bulk Actions) в списке товаров — товары с продажами не должны удаляться.

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

  • Ошибка: Товары с продажами удаляются.
    Причина: Кеширование ролей и прав в WordPress.
    Решение: После добавления фильтра сбросьте кеш прав пользователей с помощью wp_cache_flush() или повторного входа в админку.
  • Ошибка: Сообщение об ошибке не отображается при удалении через Bulk Actions.
    Причина: Ajax-запросы не всегда выводят wp_die() корректно.
    Решение: Для полного контроля создайте дополнительный фильтр для handle_bulk_actions-edit-product и возвращайте ошибку там.
  • Ошибка: Удаление не блокируется для пользовательских ролей.
    Причина: Фильтр user_has_cap может не охватывать все права.
    Решение: Проверьте, что все роли, имеющие право удалять товары, корректно обрабатываются фильтром.

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

  • Оптимизация запроса: Используйте индексы на таблицах woocommerce_order_items и woocommerce_order_itemmeta для ускорения проверки продаж.
  • Кеширование результатов: При больших магазинах кешируйте результат has_product_sales() через Transients или объектный кеш, чтобы не нагружать базу при каждом запросе.
  • Журналирование попыток удаления: Для безопасности можно добавить логирование попыток удаления товаров с продажами через error_log() или сторонние решения.
  • Тестирование на staging-сервере: Перед внедрением на живом сайте обязательно проверяйте совместимость с установленными плагинами и темой.

Сравнение вариантов реализации блокировки удаления товаров с продажами

МетодПлюсыМинусыПример
Фильтр user_has_capБлокирует удаление на уровне прав пользователя, предотвращает появление кнопки удаленияНе всегда блокирует AJAX и Bulk Actions полностьюВторой код из статьи
Хук pre_delete_postОстанавливает удаление в любом случае, включая AJAX и массовые действияСообщение об ошибке не всегда красиво отображаетсяТретий код из статьи
Плагин для контроля прав (например, User Role Editor)Удобный UI для настройки правНе решает логику проверки продаж, нужна доп. кастомизацияНеобходимо доработать
Автоматическое удаление старых transient через transient в WordPress
15.12.2025
Как создать динамические таблицы в WordPress с помощью AJAX
07.04.2026
Создание и использование ежемесячных задач в WordPress с помощью WP-Cron
11.12.2025
Как использовать хуки в WordPress для расширения функциональности
23.11.2025
Как использовать WPRemark для улучшения комментариев в WordPress
01.01.2026