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

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

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

Задача: автоматизировать удаление товаров без продаж за заданный период и с остатком на складе равным нулю, чтобы не удалять товары, которые есть в наличии, но временно не продаются.

Пошаговое решение: написание собственного WP-Cron задания

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

Функция должна:

  • Получить товары без продаж за последний, например, 180 дней;
  • Проверить остаток на складе — если он равен 0;
  • Автоматически удалить такие товары.

Пример кода для добавления в functions.php или собственный плагин:

function wpbit_delete_unsold_products_with_no_stock() {
    $days = 180;
    $date_query = array(
        'after' => date('Y-m-d', strtotime("-" . $days . " days"))
    );
    // Получаем ID товаров без продаж за $days дней
    global $wpdb;
    $query = $wpdb->prepare(
        "SELECT p.ID FROM {$wpdb->posts} p
        LEFT JOIN {$wpdb->prefix}woocommerce_order_items oi ON oi.order_id IN
            (SELECT order_id FROM {$wpdb->prefix}woocommerce_order_itemmeta oim
             WHERE oim.meta_key = '_product_id' AND oim.meta_value = p.ID)
        LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim2 ON oim2.order_item_id = oi.order_item_id
        LEFT JOIN {$wpdb->posts} o ON o.ID = oi.order_id
        WHERE p.post_type = 'product'
        AND (o.post_date < DATE_SUB(NOW(), INTERVAL %d DAY) OR o.post_date IS NULL)
        GROUP BY p.ID",
        $days
    );
    $product_ids = $wpdb->get_col($query);

    if (empty($product_ids)) {
        return; // Нет товаров для удаления
    }

    foreach ($product_ids as $product_id) {
        $stock_quantity = get_post_meta($product_id, '_stock', true);
        $manage_stock = get_post_meta($product_id, '_manage_stock', true);

        if ($manage_stock === 'yes' && intval($stock_quantity) === 0) {
            wp_delete_post($product_id, true); // Удаляем товар полностью
        }
    }
}

2. Регистрация WP-Cron события для регулярного запуска

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

if (!wp_next_scheduled('wpbit_daily_delete_unsold_products')) {
    wp_schedule_event(time(), 'daily', 'wpbit_daily_delete_unsold_products');
}

add_action('wpbit_daily_delete_unsold_products', 'wpbit_delete_unsold_products_with_no_stock');

Как проверить, что автоматическое удаление работает

  • Включите журнал ошибок PHP и посмотрите записи после выполнения Cron (или добавьте временный error_log внутрь функции);
  • Создайте тестовый товар с нулевым остатком и без продаж за нужный период — после запуска Cron он должен исчезнуть;
  • Проверьте, что товары с остатком > 0 не удаляются;
  • Запустите Cron вручную через WP-CLI: wp cron event run wpbit_daily_delete_unsold_products.

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

  • Неправильный запрос к базе данных: SQL может не учитывать все заказы из-за сложной структуры WooCommerce. Решение — тестировать запросы на вашей базе и оптимизировать фильтры.
  • Удаляются товары с остатком: проверьте метаданные _manage_stock и _stock, иногда они могут быть пустыми или неактивными — добавьте проверку if ($manage_stock !== 'yes'), чтобы пропускать такие товары.
  • Задание WP-Cron не запускается: удостоверьтесь, что на сайте есть трафик, запускающий WP-Cron, или настройте системный Cron на сервере.

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

  • Удаление товаров — необратимая операция, используйте wp_trash_post($product_id) вместо wp_delete_post для возможности восстановления;
  • Добавьте логирование удалённых товаров для аудита (например, в отдельный файл или таблицу);
  • Если каталог большой, разбивайте запрос на части с пагинацией, чтобы избежать таймаутов;
  • Для стабильной работы Cron на больших сайтах настройте системный Cron и отключите WP-Cron, избегая дублирующих запусков;
  • Периодически проверяйте наличие товаров в корзинах и заказах, чтобы не удалять товары, которые могут быть в процессе оформления.

Сравнение подходов: плагин vs код vs ручное удаление

КритерийПлагин (например, WooCommerce Cleanup)Код (как в статье)Ручное удаление
ГибкостьСредняя, зависит от возможностей плагинаМаксимальная, можно адаптировать под любые условияМинимальная, требует времени и ошибок
АвтоматизацияДа, обычно есть настройки CronПолная, по расписаниюНет
ПроизводительностьМожет быть ресурсоёмкимОптимизируемый под сайтЗависит от оператора
Риск удаления нужных товаровСредний, зависит от плагинаНизкий при правильной настройкеВысокий, человеческий фактор
Как автоматизировать удаление старых записей WordPress через шорткод
01.01.2026
Автоматизация обновления подписок в WordPress через AJAX
21.01.2026
Как автоматизировать создание резервных копий в WordPress
12.01.2026
WooCommerce: как исключить товары из корзины по атрибутам
02.05.2026
Как автоматизировать создание и удаление туториалов в WordPress
26.02.2026