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

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

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

Диагностика задачи

Перед реализацией автоматического удаления необходимо:

  • Определить, какие статусы заказов считать устаревшими (например, cancelled, failed, pending старше 30 дней).
  • Понять, какие товары удалить. Обычно это товары, которые не связаны с другими активными заказами или не продаются в других местах.
  • Оценить риски — удаление товара необратимо, нужно делать резервные копии.

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

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

1. Определяем устаревшие заказы

function get_old_orders_ids( $days = 30 ) {
    global $wpdb;
    $date_threshold = date( 'Y-m-d H:i:s', strtotime( "-{$days} days" ) );
    $statuses = array('cancelled', 'failed', 'pending');
    $placeholders = implode(',', array_fill(0, count($statuses), '%s'));

    $query = $wpdb->prepare(
        "SELECT ID FROM {$wpdb->prefix}posts WHERE post_type = 'shop_order' AND post_status IN ($placeholders) AND post_date < %s",
        ...array_merge($statuses, array($date_threshold))
    );

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

Функция возвращает ID заказов по статусам и дате.

2. Получаем товары из этих заказов

function get_products_from_orders( $order_ids ) {
    $product_ids = array();
    foreach ( $order_ids as $order_id ) {
        $order = wc_get_order( $order_id );
        if ( ! $order ) continue;
        foreach ( $order->get_items() as $item ) {
            $product_ids[] = $item->get_product_id();
        }
    }
    return array_unique( $product_ids );
}

3. Проверяем, что товары не связаны с активными заказами

Чтобы избежать удаления товаров, которые продаются в активных заказах, проверим наличие товаров в заказах со статусом processing или completed.

function filter_active_products( $product_ids ) {
    $active_statuses = array('processing', 'completed');
    $filtered = [];
    foreach ( $product_ids as $product_id ) {
        $args = array(
            'limit' => 1,
            'status' => $active_statuses,
            'product_id' => $product_id
        );
        $orders = wc_get_orders( $args );
        if ( empty( $orders ) ) {
            $filtered[] = $product_id;
        }
    }
    return $filtered;
}

4. Удаляем товары программно

Удаление товаров — это удаление постов типа product. Используем wp_delete_post() с параметром $force_delete = true, чтобы удалить без отправки в корзину.

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

5. Объединяем все шаги в задачу WP-Cron

add_action( 'wp_loaded', function() {
    if ( ! wp_next_scheduled( 'auto_delete_old_order_products' ) ) {
        wp_schedule_event( time(), 'daily', 'auto_delete_old_order_products' );
    }
});

add_action( 'auto_delete_old_order_products', function() {
    $old_orders = get_old_orders_ids(30);
    if ( empty($old_orders) ) return;

    $products = get_products_from_orders($old_orders);
    if ( empty($products) ) return;

    $to_delete = filter_active_products($products);
    if ( empty($to_delete) ) return;

    delete_products_by_ids($to_delete);
});

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

  • Проверьте наличие запланированного события в WP-Cron через плагин WP Crontrol или вручную с помощью wp cron event list.
  • Создайте тестовые заказы с разными статусами и товарами, подождите 1 день или измените дату вручную в базе, затем запустите крон вручную через WP Crontrol.
  • Убедитесь, что удаляются только товары из устаревших заказов, которые не связаны с активными заказами.
  • Проверьте логи ошибок сервера и WordPress для исключения сбоев.

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

  • Удаление нужных товаров: Не учитывается связь товара с активными заказами — добавьте проверку в filter_active_products().
  • Неправильный статус заказов: Убедитесь, что используете правильные статусы WooCommerce (например, wc-cancelled в базе — в API это cancelled).
  • Крон не запускается: Проверьте, работает ли WP-Cron, нет ли конфликтов с плагинами кеширования и не отключён ли php-функция wp-cron.php.
  • Удаление без резервных копий: Всегда делайте бэкап базы и файлов перед внедрением автоматического удаления.

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

  • Резервное копирование: Перед удалением сделайте экспорт списка товаров, чтобы можно было восстановить при ошибках.
  • Ограничение нагрузки: Если товаров много, делайте удаление пакетами по 50–100 штук с последующим повторным запуском.
  • Логирование: Добавьте логирование удалённых товаров в файл, чтобы отслеживать действия.
  • Безопасность: Ограничьте права на выполнение крона только администраторам, если запускаете вручную.

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

ВариантОписаниеПлюсыМинусы
Плагин для очистки товаров Использование готовых плагинов (например, WP Bulk Delete) Простота настройки, UI для выбора Ограниченная гибкость, нагрузка, сторонний код
Кастомный код с WP-Cron Реализация на PHP под конкретные условия Гибкость, оптимизация под задачи, прозрачность Нужно самостоятельно поддерживать, риск ошибок
Ручное удаление через админку Админ удаляет товары вручную Полный контроль Трудозатратно, не подходит для больших магазинов
Как использовать хук pre_get_posts для фильтрации записей в WordPress
20.04.2026
Оптимизация загрузки шрифтов в WordPress для ускорения сайта
20.02.2026
Как создать автоматический импорт данных из Excel в WordPress
19.03.2026
Как создать настройку переключатель темы в WordPress с применением хуков
16.12.2025
Как удалить или изменить slug кастомного типа записи в WordPress без потери данных
03.03.2026