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

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

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

Как определить товары для удаления: критерии и проверка

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

  • Количество на складе = 0 (мета поле _stock)
  • Отсутствие продаж — количество продаж товара равно 0 (мета поле total_sales)
  • Дата публикации — товар опубликован более N дней назад (чтобы не удалять новые товары)

Проверить эти параметры можно с помощью SQL-запроса к базе данных или через WP-CLI:

SELECT p.ID, p.post_title, pm1.meta_value AS stock, pm2.meta_value AS sales FROM wp_posts p
LEFT JOIN wp_postmeta pm1 ON p.ID = pm1.post_id AND pm1.meta_key = '_stock'
LEFT JOIN wp_postmeta pm2 ON p.ID = pm2.post_id AND pm2.meta_key = 'total_sales'
WHERE p.post_type = 'product' AND p.post_status = 'publish'
AND pm1.meta_value = '0' AND pm2.meta_value = '0'
AND p.post_date < DATE_SUB(NOW(), INTERVAL 30 DAY);

Этот запрос покажет товары с нулевым остатком и без продаж старше 30 дней.

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

Оптимальный способ — создать функцию, которая удаляет товары по критериям, и запускать её раз в сутки через WP-Cron.

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

function wps_delete_unsold_out_of_stock_products() {
    $args = [
        'post_type'      => 'product',
        'posts_per_page' => -1,
        'post_status'    => 'publish',
        'date_query'     => [
            [
                'before' => '30 days ago',
            ],
        ],
        'meta_query'     => [
            'relation' => 'AND',
            [
                'key'     => '_stock',
                'value'   => '0',
                'compare' => '=',
                'type'    => 'NUMERIC',
            ],
            [
                'key'     => 'total_sales',
                'value'   => '0',
                'compare' => '=',
                'type'    => 'NUMERIC',
            ],
        ],
        'fields'         => 'ids',
    ];

    $products = get_posts($args);

    foreach ($products as $product_id) {
        wp_delete_post($product_id, true);
    }
}

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

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

add_action('wps_daily_product_cleanup_hook', 'wps_delete_unsold_out_of_stock_products');

3. Как добавить задачу вручную (для отладки)

// Временно вызвать функцию вручную
add_action('init', function() {
    if (isset($_GET['run_product_cleanup'])) {
        wps_delete_unsold_out_of_stock_products();
        exit('Cleanup done');
    }
});

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

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

  • Добавьте тестовый товар с нулевым остатком и нулевыми продажами, опубликованный более 30 дней назад.
  • Запустите вручную функцию через URL вида https://example.com/?run_product_cleanup
  • Проверьте, что товар исчез из админки и базы (таблица wp_posts).
  • Проверьте логи сервера на наличие ошибок PHP.

Для контроля можно добавить логирование удалённых товаров, например:

function wps_delete_unsold_out_of_stock_products() {
    $args = [...]; // как выше
    $products = get_posts($args);
    foreach ($products as $product_id) {
        error_log('Deleted product ID: ' . $product_id);
        wp_delete_post($product_id, true);
    }
}

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

  • Функция не удаляет товары: Проверьте правильность meta_key и значения _stock и total_sales. Иногда запас хранится в другом мета поле, например, _manage_stock или используются сторонние плагины, меняющие логику.
  • Удаляются не все нужные товары: Ограничение по дате может быть слишком жёстким, попробуйте увеличить или убрать фильтр date_query.
  • WP-Cron не срабатывает: Проверьте, что на сайте посещения достаточные для запуска WP-Cron или настройте системный cronjob для запуска wp-cron.php.
  • Удаление товаров приводит к ошибкам: Убедитесь, что wp_delete_post() вызывается с параметром true для принудительного удаления без перемещения в корзину.

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

  • Перед автоматическим удалением делайте резервную копию базы данных, особенно если у вас большой каталог.
  • Для больших магазинов используйте постраничный вывод (posts_per_page с лимитом и пагинацией), чтобы не перегружать память.
  • Используйте транзиенты или логи для мониторинга количества удалённых товаров и предотвращения повторных удалений.
  • Для безопасности ограничьте запуск ручных вызовов функции проверкой nonce или прав администратора.
  • Если используете WPShop Clearfy Pro, дополнительно можно настроить очистку базы от устаревших метаданных и записей.

Сравнение методов автоматического удаления товаров

МетодПреимуществаНедостатки
WP-Cron + свой кодГибкость, контроль, не требует сторонних плагиновЗависит от посещаемости сайта, требует отладки
Плагины очистки базы (например, Clearfy Pro)Удобный интерфейс, дополнительные функции оптимизацииМожет стоить денег, ограниченная кастомизация
Ручное удаление через SQLБыстрое решение для опытных администраторовВысокий риск, требует бэкапа, не автоматично
Как удалить CSS класс из элемента в WordPress с помощью JavaScript
13.03.2026
Как создать автоматическое резервное копирование WordPress с помощью плагинов и собственного кода
28.11.2025
Как создать собственный шорткод в WordPress
01.11.2025
Как использовать WP Background Processing в WordPress для обработки задач в фоне
30.03.2026
WooCommerce: как избежать проблемы с кешированием и отображением товаров при фильтрации AJAX
16.05.2026