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

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

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

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

Для начала нужно понять, что считать «неактивным». Обычно это товары, которые не обновлялись или не имели заказов в течение определенного периода (например, 6 месяцев). Сравните даты post_modified и заказы в таблице wp_woocommerce_order_items.

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

Рассмотрим скрипт, который по крону удалит товары, не обновлявшиеся более 180 дней. Удалять будем товары с типом product и статусом publish.

function wpt_delete_old_products() {
    $days = 180; // количество дней неактивности
    $date_threshold = date('Y-m-d H:i:s', strtotime("-{$days} days"));

    $args = [
        'post_type'      => 'product',
        'post_status'    => 'publish',
        'date_query'     => [
            [
                'column' => 'post_modified',
                'before' => $date_threshold,
            ],
        ],
        'posts_per_page' => -1,
        'fields'         => 'ids',
    ];

    $query = new WP_Query($args);
    if ($query->have_posts()) {
        foreach ($query->posts as $product_id) {
            wp_delete_post($product_id, true); // принудительно удаляем без корзины
        }
    }
}

// Регистрация ежесуточного события
if (!wp_next_scheduled('wpt_daily_delete_old_products')) {
    wp_schedule_event(time(), 'daily', 'wpt_daily_delete_old_products');
}
add_action('wpt_daily_delete_old_products', 'wpt_delete_old_products');

Этот код можно добавить в файл functions.php вашей темы или в отдельный плагин.

Как учесть заказы и продажи

Удалять товары, которые продаются, нежелательно. Для этого нужно исключить товары, которые были в заказах за последние N дней.

function wpt_get_sold_products_last_days($days) {
    global $wpdb;
    $date_after = date('Y-m-d H:i:s', strtotime("-{$days} days"));

    $query = $wpdb->prepare(
        "SELECT DISTINCT order_item_meta.meta_value FROM {$wpdb->prefix}woocommerce_order_items AS order_items
        
        INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta ON order_items.order_item_id = order_item_meta.order_item_id
        
        INNER JOIN {$wpdb->prefix}posts AS orders ON orders.ID = order_items.order_id
        
        WHERE orders.post_type = 'shop_order'
        AND orders.post_status IN ('wc-completed','wc-processing')
        AND orders.post_date > %s
        AND order_item_meta.meta_key = '_product_id'",
        $date_after
    );

    return $wpdb->get_col($query);
}

function wpt_delete_old_products_exclude_sold() {
    $days = 180;
    $date_threshold = date('Y-m-d H:i:s', strtotime("-{$days} days"));
    $sold_products = wpt_get_sold_products_last_days($days);

    $args = [
        'post_type'      => 'product',
        'post_status'    => 'publish',
        'date_query'     => [
            [
                'column' => 'post_modified',
                'before' => $date_threshold,
            ],
        ],
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'post__not_in'   => $sold_products,
    ];

    $query = new WP_Query($args);
    if ($query->have_posts()) {
        foreach ($query->posts as $product_id) {
            wp_delete_post($product_id, true);
        }
    }
}

if (!wp_next_scheduled('wpt_daily_delete_old_products')) {
    wp_schedule_event(time(), 'daily', 'wpt_daily_delete_old_products');
}
add_action('wpt_daily_delete_old_products', 'wpt_delete_old_products_exclude_sold');

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

  • В админке WooCommerce проверьте количество товаров до и после запуска скрипта.
  • Для ручного теста вызовите функцию через do_action('wpt_daily_delete_old_products') в консоли WP-CLI или добавьте временный вызов в код.
  • Проверьте логи ошибок, чтобы убедиться, что нет фатальных ошибок.
  • Просмотрите базу данных через phpMyAdmin или WP CLI, чтобы убедиться, что старые товары удалены.

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

  • Удаляются активные товары: проверьте условия исключения товаров с продажами и, если нужно, расширьте исключения по меткам или категориям.
  • Скрипт не запускается: убедитесь, что wp-cron работает, или настройте системный CRON для вызова wp-cron.php.
  • Удаление занимает слишком много времени: используйте постраничный запрос (например, по 50 товаров за раз) и запускайте удаление в несколько шагов.
  • Потеря данных: всегда делайте резервную копию перед массовым удалением.

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

  • Добавьте логирование: записывайте ID удаляемых товаров в отдельный файл, чтобы при необходимости восстановить информацию.
  • Используйте транзакции базы данных, если планируете более сложные операции.
  • Для больших магазинов лучше разделить скрипт на несколько частей с пагинацией.
  • Не удаляйте товары навсегда сразу — сначала переводите их в статус черновика (draft) и проверяйте результаты.

Сравнение подходов: плагин vs кастомный код

МетодПлюсыМинусыКомпромисс
Готовый плагин очисткиПростота установки, UI для настройкиМожет удалять не то, что нужно; нагрузка; ограниченная кастомизацияИспользуйте с фильтрами и тестированием
Кастомный код (пример из статьи)Точная настройка; минимальная нагрузка; можно интегрировать в процессыТребует навыков PHP и тестированияОптимален для опытных разработчиков
Как создать собственный плагин для WordPress с примерами кода
02.12.2025
Как удалить или заблокировать плагин WordPress, если стандартные методы не работают
24.01.2026
Как создать собственный вид регистрации в WordPress с примерами кода и плагинов
25.11.2025
Как создать динамический виджет в WordPress с использованием PHP и хуков
18.11.2025
Создаем свой шаблон для WordPress с нуля
04.11.2025