wp-lessons.ru wordpress WP-Lessons

WooCommerce: автоматическое отключение товаров без продаж за определённый период

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

Интернет-магазины с большим каталогом товаров сталкиваются с проблемой «зависших» товаров — тех, которые не продаются длительное время. Они занимают место в каталоге, ухудшают пользовательский опыт и могут влиять на SEO. Ручное отключение таких товаров — трудоёмкий процесс. Автоматизация решения этой задачи помогает поддерживать актуальность ассортимента и улучшать конверсию.

Как определить товары без продаж за период

Для начала нужно получить список товаров, которые не имели продаж за заданный промежуток времени. В WooCommerce данные о заказах хранятся в таблицах wp_posts (заказы) и wp_woocommerce_order_items (товары в заказах). Чтобы получить товары без продаж, нужно:

  • Выбрать все товары (продукты) из wp_posts с типом product.
  • Получить список товаров, которые были в заказах со статусом wc-completed или wc-processing за период.
  • Отфильтровать товары, которые не встречаются в заказах за этот период.

Для примера можно использовать WP_Query и SQL-запросы, но проще оперировать через PHP и WooCommerce API.

Пошаговое решение с примером кода

1. Создаём функцию для получения ID товаров без продаж

function get_products_without_sales( $days = 30 ) {
    global $wpdb;
    $date_from = date('Y-m-d H:i:s', strtotime("-" . intval($days) . " days"));

    // Получаем ID товаров, проданных за период
    $sold_products = $wpdb->get_col( $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 posts ON order_items.order_id = posts.ID
         
         WHERE order_item_meta.meta_key = '_product_id'
           AND posts.post_type = 'shop_order'
           AND posts.post_status IN ('wc-completed', 'wc-processing')
           AND posts.post_date >= %s
        ", $date_from
    ) );

    if ( empty( $sold_products ) ) {
        // Если продаж не было, возвращаем всех опубликованных товаров
        $all_products = get_posts( [
            'post_type' => 'product',
            'posts_per_page' => -1,
            'fields' => 'ids',
            'post_status' => 'publish',
        ] );
        return $all_products;
    }

    // Получаем все опубликованные товары
    $all_products = get_posts( [
        'post_type' => 'product',
        'posts_per_page' => -1,
        'fields' => 'ids',
        'post_status' => 'publish',
    ] );

    // Возвращаем товары, которых нет в списке проданных
    return array_diff( $all_products, $sold_products );
}

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

function disable_unsold_products( $days = 30 ) {
    $products_to_disable = get_products_without_sales( $days );
    
    foreach ( $products_to_disable as $product_id ) {
        // Меняем статус на 'draft' — товар будет снят с публикации
        wp_update_post( [
            'ID' => $product_id,
            'post_status' => 'draft',
        ] );
    }
}

3. Запускаем функцию через WP-Cron или вручную

Для автоматизации добавьте задачу в WP-Cron:

if ( ! wp_next_scheduled( 'auto_disable_unsold_products_daily' ) ) {
    wp_schedule_event( time(), 'daily', 'auto_disable_unsold_products_daily' );
}

add_action( 'auto_disable_unsold_products_daily', function() {
    disable_unsold_products( 30 ); // отключаем товары без продаж за 30 дней
} );

Или вызовите disable_unsold_products(30) вручную для проверки.

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

  • Перейдите в админ-панель WooCommerce → Товары и отфильтруйте по статусу «Черновик». Должны появиться товары, которые не продавались последние 30 дней.
  • Проверьте, что эти товары действительно не были проданы за период, сверив продажи.
  • После повторного запуска через период товары без продаж должны автоматически становиться черновиками.

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

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

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

  • При массовом обновлении товаров лучше обрабатывать данные партиями, чтобы не перегружать сервер.
  • Тестируйте код сначала на тестовой копии сайта, чтобы избежать случайного закрытия важных товаров.
  • Периодично очищайте задачи WP-Cron, чтобы не создавать дубли и не перегружать систему.
  • Используйте транзиенты или кэширование для уменьшения нагрузки на базу при частых вызовах.

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

КритерийПлагинСобственный кодКомпромисс
ГибкостьОграничена настройкамиПолная, под свои нуждыБольше времени на разработку
НагрузкаМожет быть высокой из-за универсальностиОптимизирован под задачуТребует навыков оптимизации
ОбновленияАвтоматическиеНеобходим контрольМожно автоматизировать через систему контроля версий
БезопасностьЗависит от разработчика плагинаКонтролируете самиНеобходимо тестирование и аудит
×
WPRemark
Внимание Внимание Внимание Внимание
-15%

на WPRemark плагин WordPress

Прокачай свой сайт! ⋙