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

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

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

Пошаговое решение: скрипт для удаления товаров без заказов

1. Определение товаров без заказов

Для начала нужно получить список товаров, у которых нет связанных заказов. Для этого используем SQL-запрос или WP_Query с условием на наличие заказов.

2. Создание функции удаления

Добавим функцию, которая удалит товары без заказов, используя стандартную функцию wp_delete_post().

function wc_delete_products_without_orders() {
    global $wpdb;

    // Получаем ID товаров, не входящих ни в один заказ
    $product_ids = $wpdb->get_col(
        "SELECT p.ID FROM {$wpdb->posts} p
         LEFT JOIN {$wpdb->prefix}woocommerce_order_items oi ON oi.order_item_name = p.ID
         LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id
         WHERE p.post_type = 'product'
         AND p.post_status = 'publish'
         AND oim.meta_key = '_product_id'
         AND oim.meta_value IS NULL"
    );

    if (empty($product_ids)) {
        return 'Нет товаров без заказов';
    }

    foreach ($product_ids as $product_id) {
        wp_delete_post($product_id, true); // Принудительно удаляем
    }

    return count($product_ids) . ' товаров удалено';
}

3. Запуск функции по расписанию с помощью WP-Cron

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

function wc_schedule_delete_products_event() {
    if (!wp_next_scheduled('wc_delete_products_event')) {
        wp_schedule_event(time(), 'weekly', 'wc_delete_products_event');
    }
}
add_action('wp', 'wc_schedule_delete_products_event');

add_action('wc_delete_products_event', 'wc_delete_products_without_orders');

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

  • Перейдите в раздел «Товары» в админке WooCommerce и проверьте, что товары без заказов удалены.
  • Проверьте журнал событий WP-Cron через плагин WP Crontrol, чтобы убедиться, что задача запущена.
  • Выполните функцию вручную через консоль WP-CLI для теста: wp eval 'echo wc_delete_products_without_orders();'

Частые ошибки и способы их исправления

  • Ошибка: Пустой список товаров для удаления
    Причина: Некорректный SQL-запрос или не учитываются статусы заказов.
    Решение: Проверьте запрос, убедитесь, что учитываются все статусы заказов, например, 'wc-completed', 'wc-processing'.
  • Ошибка: Функция не запускается по расписанию
    Причина: WP-Cron отключен или неактивен.
    Решение: Проверьте, что на сайте есть трафик, или настройте системный cron для вызова wp-cron.php.
  • Ошибка: Удаляются нужные товары
    Причина: Логика определения товаров без заказов слишком грубая.
    Решение: Добавьте дополнительные проверки, например, на дату создания товара или наличие атрибутов.

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

  • Перед удалением товаров сделайте резервную копию базы данных.
  • Добавьте проверку времени создания товара, чтобы не удалять недавно добавленные товары (например, младше 30 дней).
  • Для больших каталогов используйте пакетную обработку по 50-100 товаров за раз, чтобы избежать таймаутов.
  • Для мониторинга создайте лог удалённых товаров, чтобы иметь возможность восстановить данные.

Пример улучшенной функции с проверкой даты и пакетной обработкой

function wc_delete_old_products_without_orders_batch($batch_size = 50) {
    global $wpdb;
    $date_threshold = date('Y-m-d H:i:s', strtotime('-30 days'));

    $product_ids = $wpdb->get_col($wpdb->prepare(
        "SELECT p.ID FROM {$wpdb->posts} p
         WHERE p.post_type = 'product'
         AND p.post_status = 'publish'
         AND p.post_date < %s
         AND NOT EXISTS (
             SELECT 1 FROM {$wpdb->prefix}woocommerce_order_itemmeta oim
             JOIN {$wpdb->prefix}woocommerce_order_items oi ON oim.order_item_id = oi.order_item_id
             JOIN {$wpdb->prefix}posts o ON oi.order_id = o.ID
             WHERE o.post_status IN ('wc-completed', 'wc-processing')
             AND oim.meta_key = '_product_id'
             AND oim.meta_value = p.ID
         )
         LIMIT %d",
         $date_threshold,
         $batch_size
    ));

    if (empty($product_ids)) {
        return 'Нет товаров для удаления в этом пакете';
    }

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

    return count($product_ids) . ' товаров удалено в этом пакете';
}

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

МетодПлюсыМинусыКогда использовать
Полный SQL-запрос и удаление сразуБыстрое удаление всех товаровРиск таймаутов, нет контроля по времениМаленький каталог, разовая чистка
Пакетная обработка с проверкой датыБезопасно, контролируемо, можно запускать регулярноСложнее в реализацииБольшие каталоги, регулярное обслуживание
Ручное удаление через админкуПростой контрольТрудоемко, неавтоматичноМалое количество товаров, редко
Автоматизация обновлений тем и пингов в WordPress на WPengine
08.03.2026
Как установить ограничение на регистрацию пользователей в WordPress
02.04.2026
Автоматизация отключения неиспользуемых плагинов в WordPress на WPengine
26.01.2026
WooCommerce: решение проблем с автоматическим удалением товаров без заказов
28.05.2026
Как избежать конфликтов между плагинами в WordPress: практические советы и примеры
15.03.2026