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

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

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

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

Непроданные товары — это те, у которых за последний N дней не было ни одной продажи. Для определения продаж товаров проверяем таблицу заказов wp_posts (post_type = 'shop_order') и связанные метаданные в wp_postmeta, где хранятся статусы заказов и позиции товаров.

В WooCommerce для подсчёта продаж учитываем только заказанные и завершённые заказы, статусы которых 'completed' или 'processing'.

Запрос для получения ID непроданных товаров

SELECT p.ID FROM wp_posts p
LEFT JOIN (
  SELECT oi.order_item_id, oim.meta_value AS product_id
  FROM wp_woocommerce_order_items oi
  JOIN wp_woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id AND oim.meta_key = '_product_id'
  JOIN wp_posts o ON oi.order_id = o.ID
  WHERE o.post_type = 'shop_order'
    AND o.post_status IN ('wc-completed', 'wc-processing')
    AND o.post_date > DATE_SUB(NOW(), INTERVAL 90 DAY)
) sold ON p.ID = sold.product_id
WHERE p.post_type = 'product' AND sold.product_id IS NULL;

Этот запрос выбирает товары без продаж за последние 90 дней.

Пошаговое решение: автоматическое удаление непроданных товаров через WP-Cron

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

function wpbit_delete_unsold_products() {
    global $wpdb;
    $days = 90; // Период в днях

    // Получаем ID товаров без продаж за период
    $query = $wpdb->prepare(
        "SELECT p.ID FROM {$wpdb->posts} p
        LEFT JOIN (
          SELECT oi.order_item_id, oim.meta_value AS product_id
          FROM {$wpdb->prefix}woocommerce_order_items oi
          JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id AND oim.meta_key = '_product_id'
          JOIN {$wpdb->posts} o ON oi.order_id = o.ID
          WHERE o.post_type = 'shop_order'
            AND o.post_status IN ('wc-completed', 'wc-processing')
            AND o.post_date > DATE_SUB(NOW(), INTERVAL %d DAY)
        ) sold ON p.ID = sold.product_id
        WHERE p.post_type = 'product' AND sold.product_id IS NULL;",
        $days
    );

    $product_ids = $wpdb->get_col($query);

    if (empty($product_ids)) {
        return;
    }

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

2. Регистрируем WP-Cron задачу

function wpbit_schedule_delete_unsold_products() {
    if (!wp_next_scheduled('wpbit_daily_delete_unsold_products')) {
        wp_schedule_event(time(), 'daily', 'wpbit_daily_delete_unsold_products');
    }
}
add_action('wp', 'wpbit_schedule_delete_unsold_products');

add_action('wpbit_daily_delete_unsold_products', 'wpbit_delete_unsold_products');

3. Запуск и отключение задачи по необходимости

Для деактивации cron-задачи можно использовать:

function wpbit_clear_scheduled_delete() {
    $timestamp = wp_next_scheduled('wpbit_daily_delete_unsold_products');
    if ($timestamp) {
        wp_unschedule_event($timestamp, 'wpbit_daily_delete_unsold_products');
    }
}

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

  • Проверить наличие запланированной задачи в разделе wp-cron.scheduled с помощью плагинов (например, WP Crontrol).
  • Запустить функцию вручную через консоль или добавить временный вызов wpbit_delete_unsold_products() и убедиться, что непроданные товары удаляются.
  • Проверить базу данных на отсутствие товаров без продаж старше 90 дней.

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

  • Неверные статусы заказов: учитывайте только 'wc-completed' и 'wc-processing'. Если добавить 'wc-pending' или 'wc-on-hold', товары могут удаляться некорректно.
  • Проблемы с WP-Cron: если на сайте низкий трафик, cron-задачи не выполняются вовремя. Настройте системный cron или используйте плагин WP Crontrol для тестирования.
  • Удаление товаров с вариациями: функция удаляет только главные продукты, вариации удаляются вместе с ними. Если вариации используются отдельно, нужно адаптировать код.
  • Потеря данных: удаление происходит без возможности восстановления. Рекомендуется делать резервные копии базы данных перед запуском.

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

  • Используйте wp_delete_post($id, true) для полного удаления, но убедитесь в необходимости, чтобы не потерять важные данные.
  • Ограничьте период в днях для удаления, чтобы не удалять недавно добавленные товары.
  • Для больших магазинов с тысячами товаров выполняйте удаление пакетами, например, по 50 товаров за один запуск, чтобы снизить нагрузку.
  • Добавьте логирование удалённых товаров в отдельный файл или в таблицу базы для аудита и восстановления при необходимости.

Сравнение вариантов реализации удаления непроданных товаров

МетодПлюсыМинусы
WP-Cron с кастомным кодомГибкость, можно настроить период, фильтры, удаление по критериямЗависит от работы WP-Cron, нагрузка при больших объемах
Плагины очистки WooCommerceПростота установки, интерфейс, дополнительные функции (очистка корзины, заказов)Могут быть избыточными, не всегда поддерживают точные условия удаления
Ручное удаление через SQL-запросыБыстро и сразуРиск ошибок, потеря данных, сложность в поддержке
Как создать собственный тип записи в WordPress
24.11.2025
Автоматическое изменение метаданных SEO в WordPress
22.03.2026
Как автоматически удалять неактивных пользователей WordPress
07.02.2026
Как автоматически изменять заголовки постов WordPress по шаблону
10.03.2026
Как установить и очистить заголовки H1 в WordPress без пустых тегов
29.12.2025