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

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

В интернет-магазинах на WooCommerce накапливаются товары, которые давно не продаются, устарели или не имеют заказов. Их хранение увеличивает объем базы данных, замедляет админку и мешает клиентам ориентироваться. Частая задача — автоматизировать удаление таких товаров по заданным правилам, например, если товар не продавался более 6 месяцев или не обновлялся.

Перед автоматизацией важно проверить, что именно считать «неактивным» товаром. Обычно критерии:

  • Отсутствие заказов за последние N месяцев.
  • Дата последнего обновления товара старше заданной.
  • Статус товара — опубликован, черновик, или архив.

Как получить список неактивных товаров: WP_Query и SQL-запросы

Для начала нужно получить ID товаров, подходящих под критерии. Пример запроса на WP_Query для товаров без заказов за 6 месяцев:

$cutoff_date = date('Y-m-d', strtotime('-6 months'));

$args = [
    'post_type' => 'product',
    'posts_per_page' => -1,
    'date_query' => [
        [
            'column' => 'post_modified',
            'before' => $cutoff_date,
        ],
    ],
    'meta_query' => [
        [
            'key' => '_last_order_date', // кастомное поле с датой последнего заказа
            'value' => $cutoff_date,
            'compare' => '<=',
            'type' => 'DATE',
        ],
    ],
];

$query = new WP_Query($args);
$inactive_products = $query->posts;

Важно: WooCommerce по умолчанию не хранит дату последнего заказа в метаполях товара, поэтому нужно самостоятельно обновлять поле _last_order_date при каждом заказе товара (см. следующий раздел).

Автоматическое обновление даты последнего заказа товара

Чтобы отслеживать дату последнего заказа, добавим хуки, которые обновляют метаполе товара при оформлении заказа:

add_action('woocommerce_order_status_completed', 'update_last_order_date_for_products');

function update_last_order_date_for_products($order_id) {
    $order = wc_get_order($order_id);
    if (!$order) return;

    foreach ($order->get_items() as $item) {
        $product_id = $item->get_product_id();
        update_post_meta($product_id, '_last_order_date', current_time('Y-m-d'));
    }
}

Этот код записывает текущую дату в метаполе _last_order_date у каждого товара из заказа при его завершении.

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

Чтобы не запускать удаление вручную, создадим WP-Cron задачу, которая будет выполняться, например, раз в неделю.

1. Добавляем функцию удаления

function delete_inactive_products() {
    $cutoff_date = date('Y-m-d', strtotime('-6 months'));

    $args = [
        'post_type' => 'product',
        'posts_per_page' => -1,
        'date_query' => [
            [
                'column' => 'post_modified',
                'before' => $cutoff_date,
            ],
        ],
        'meta_query' => [
            [
                'key' => '_last_order_date',
                'value' => $cutoff_date,
                'compare' => '<=',
                'type' => 'DATE',
            ],
            [
                'key' => '_last_order_date',
                'compare' => 'EXISTS'
            ],
        ],
    ];

    $query = new WP_Query($args);
    foreach ($query->posts as $product) {
        wp_delete_post($product->ID, true); // true — безвозвратное удаление
    }
}

2. Регистрируем WP-Cron событие

add_action('delete_inactive_products_event', 'delete_inactive_products');

if (!wp_next_scheduled('delete_inactive_products_event')) {
    wp_schedule_event(time(), 'weekly', 'delete_inactive_products_event');
}

3. Проверяем работу и логи

Для отладки полезно добавить логирование (например, в файл wp-content/debug.log):

function delete_inactive_products() {
    if (!defined('WP_DEBUG') || !WP_DEBUG) return;

    $cutoff_date = date('Y-m-d', strtotime('-6 months'));
    $args = [...]; // см. выше

    $query = new WP_Query($args);
    foreach ($query->posts as $product) {
        error_log('Удаление товара ID: ' . $product->ID);
        wp_delete_post($product->ID, true);
    }
}

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

  • Проверьте наличие товаров с датой последнего заказа старше 6 месяцев и датой обновления поста.
  • Запустите функцию удаления вручную, вызвав delete_inactive_products() через консоль WP-CLI или временно в коде.
  • Проверьте, что товары удаляются (их нет в админке и базе).
  • Если используете логирование, проверьте debug.log на записи об удалении.
  • Для мониторинга WP-Cron используйте плагин WP Crontrol, чтобы увидеть запланированные задачи.

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

  • Нет метаполя _last_order_date: WooCommerce не создает его по умолчанию, нужно добавить код из раздела «Автоматическое обновление даты последнего заказа».
  • Функция удаления не запускается: проверьте, активен ли WP-Cron и не блокируется ли планировщик хостингом. Для теста запустите вручную.
  • Удаляются нужные товары: убедитесь в правильности условий date_query и meta_query. Добавьте логирование для контроля.
  • Удаление слишком медленное: разбейте запрос на части с posts_per_page и запускайте удаление пакетами.

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

  • Перед удалением сделайте бэкап базы данных.
  • Используйте wp_delete_post($id, true) для полного удаления, иначе товары попадут в корзину.
  • Для крупных магазинов разбивайте удаление на партии с паузами, чтобы не перегружать сервер.
  • Добавьте проверку прав пользователя, если функция будет запускаться вручную через админку.
  • Оптимизируйте запросы, индексируйте метаполя, чтобы ускорить выборку.
  • При необходимости замените WP-Cron на системный cron для стабильности.

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

ПодходПлюсыМинусыПримечания
Плагин автоудаления товаровПростота настройки, интерфейсМожет быть избыточным, нагрузка, ограничения по логикеПодходит для простых задач
Код на сайте (WP-Cron + WP_Query)Гибкость, контроль, оптимизация под задачиТребует знаний, риски ошибокЛучше для крупных магазинов и нестандартных условий
Комбинация: плагин + кастомный кодУдобство + гибкостьСложнее отладка, возможны конфликтыДля опытных разработчиков
×
Прокачай свой сайт WordPress!

WordPress

-20% на премиум темы и плагины

Создай сайт своей мечты ⋙