WooCommerce: автоматическое удаление товаров без заказов

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

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

Как определить товары без заказов в WooCommerce

Для начала нужно понять, какие товары не имеют заказов. Основная связь между заказами и товарами хранится в таблицах wp_woocommerce_order_items и wp_woocommerce_order_itemmeta. Простой SQL-запрос поможет получить ID товаров, которые были заказаны:

SELECT DISTINCT order_item_id, meta_value as product_id
FROM wp_woocommerce_order_items
JOIN wp_woocommerce_order_itemmeta ON wp_woocommerce_order_items.order_item_id = wp_woocommerce_order_itemmeta.order_item_id
WHERE meta_key = '_product_id';

Чтобы найти товары без заказов — нужно получить список всех товаров и исключить из него те, что встречаются в заказах.

Пошаговое решение: автоматическое удаление товаров без заказов

1. Создайте функцию для проверки товаров без заказов

function get_products_without_orders($days = 30) {
    global $wpdb;

    // Получаем ID товаров, которые были заказаны за последние $days дней
    $date_threshold = date('Y-m-d H:i:s', strtotime("-{$days} days"));

    $ordered_products = $wpdb->get_col($wpdb->prepare(
        "SELECT DISTINCT meta_value FROM {$wpdb->prefix}woocommerce_order_items oi
        
        INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
        
        INNER JOIN {$wpdb->prefix}posts p ON oi.order_id = p.ID
        
        WHERE oim.meta_key = '_product_id' AND p.post_type = 'shop_order' AND p.post_status IN ('wc-completed', 'wc-processing') AND p.post_date >= %s",
        $date_threshold
    ));

    // Получаем все ID товаров
    $all_products = get_posts([
        'post_type' => 'product',
        'posts_per_page' => -1,
        'fields' => 'ids',
        'post_status' => 'publish',
    ]);

    // Возвращаем товары, которых нет в заказах
    return array_diff($all_products, $ordered_products);
}

2. Функция удаления товаров

function delete_products_by_ids(array $product_ids) {
    foreach ($product_ids as $product_id) {
        wp_delete_post($product_id, true); // Принудительно удаляем без возможности восстановления
    }
}

3. Настройка WP-Cron для автоматизации

Добавьте в functions.php или собственный плагин следующий код для еженедельного запуска задачи удаления товаров без заказов:

add_action('wp_delete_products_without_orders', 'wp_delete_unused_products_cron');

function wp_delete_unused_products_cron() {
    $products_to_delete = get_products_without_orders(30); // Товары без заказов за последние 30 дней
    if (!empty($products_to_delete)) {
        delete_products_by_ids($products_to_delete);
    }
}

// Регистрируем событие при активации плагина/темы
function wp_schedule_delete_products_event() {
    if (!wp_next_scheduled('wp_delete_products_without_orders')) {
        wp_schedule_event(time(), 'weekly', 'wp_delete_products_without_orders');
    }
}
add_action('wp', 'wp_schedule_delete_products_event');

// Снимаем расписание при деактивации
function wp_unschedule_delete_products_event() {
    $timestamp = wp_next_scheduled('wp_delete_products_without_orders');
    if ($timestamp) {
        wp_unschedule_event($timestamp, 'wp_delete_products_without_orders');
    }
}

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

  • Через панель администратора WooCommerce зайдите в раздел Товары и проверьте, что товары без заказов старше 30 дней исчезли.
  • Запустите вручную функцию с помощью WP-CLI:
    wp eval 'wp_delete_unused_products_cron();' и проверьте удаление.
  • Проверьте лог ошибок PHP и WooCommerce на предмет проблем при удалении.

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

  • Не удаляются товары: проверьте права пользователя, под которым запущен WP-Cron или WP-CLI. Убедитесь, что функция wp_delete_post вызывается с правильным ID и вторым параметром true для безвозвратного удаления.
  • Товары с заказами тоже удаляются: проверьте корректность SQL-запроса. Убедитесь, что статусы заказов правильно фильтруются (например, исключая отменённые)
  • Нагрузка на базу данных: для магазинов с тысячами товаров запросы могут быть тяжёлыми. Используйте пагинацию при выборке товаров.

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

  • Перед удалением товаров делайте резервную копию базы данных.
  • Проверяйте статус заказов — учитывайте только оплаченные и обработанные.
  • Оптимизируйте запросы с помощью индексов в базе данных.
  • Для больших магазинов разбивайте удаление на партии (например, по 50 товаров за раз).
  • Логируйте удалённые товары для последующего аудита.

Сравнение вариантов удаления товаров без заказов

МетодОписаниеПлюсыМинусы
Ручное удаление через админкуПоиск и удаление товаров вручнуюПростой способ без кодаТрудоёмко, неэффективно при большом каталоге
Плагин для очистки базыИспользование готовых плагинов для удаления неактивных товаровУдобство, дополнительные функцииМожет замедлять сайт, лишний плагин
Кодовое решение с WP-Cron (данный метод)Автоматизация удаления через собственный скриптКонтроль, гибкость, отсутствие лишних плагиновНеобходимы навыки разработки, риск ошибок
Как сделать производительный AJAX в WordPress без admin-ajax.php
06.04.2026
WooCommerce: как решить проблему не отправляющихся писем о подтверждении заказа
16.06.2026
Как использовать хук pre_get_posts для фильтрации запросов в WordPress
19.03.2026
Как удалить неиспользуемые посты в WordPress автоматически
08.03.2026
Как создать автоматическое наступление событий после публикации в WordPress
19.01.2026