wp-lessons.ru wordpress WP-Lessons

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

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

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

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

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

На практике проще использовать WP_Query с фильтрацией по метаданным или прямые SQL-запросы. Ниже пример SQL-запроса для получения ID товаров без продаж за последние 90 дней:

SELECT p.ID FROM wp_posts p
WHERE p.post_type = 'product'
AND p.post_status = 'publish'
AND p.ID NOT IN (
    SELECT DISTINCT order_item_meta.meta_value
    FROM wp_woocommerce_order_items order_items
    
    INNER JOIN wp_woocommerce_order_itemmeta order_item_meta ON order_items.order_item_id = order_item_meta.order_item_id
    INNER JOIN wp_posts orders ON orders.ID = order_items.order_id
    
    WHERE order_item_meta.meta_key = '_product_id'
    AND orders.post_type = 'shop_order'
    AND orders.post_status IN ('wc-completed', 'wc-processing')
    AND orders.post_date >= DATE_SUB(NOW(), INTERVAL 90 DAY)
);

Этот запрос возвращает ID товаров, которые не продавались за последние 90 дней и сейчас опубликованы.

Пошаговое решение: отключаем неактивные товары программно

Реализуем задачу через WP-Cron, который ежесуточно проверяет и переводит неактивные товары в статус draft (отключает публикацию). Пример кода для файла functions.php или собственного плагина:

function disable_inactive_products() {
    global $wpdb;
    $days = 90; // Период без продаж

    $query = $wpdb->prepare(
        "SELECT p.ID FROM {$wpdb->posts} p
         WHERE p.post_type = 'product'
         AND p.post_status = 'publish'
         AND p.ID NOT IN (
             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->posts} AS orders ON orders.ID = order_items.order_id
             WHERE order_item_meta.meta_key = '_product_id'
             AND orders.post_type = 'shop_order'
             AND orders.post_status IN ('wc-completed', 'wc-processing')
             AND orders.post_date >= DATE_SUB(NOW(), INTERVAL %d DAY)
         )",
         $days
    );

    $product_ids = $wpdb->get_col($query);

    if (!empty($product_ids)) {
        foreach ($product_ids as $product_id) {
            // Обновляем статус товара на draft
            wp_update_post(array(
                'ID' => $product_id,
                'post_status' => 'draft'
            ));
        }
    }
}

// Регистрируем ежедневное событие при активации темы или плагина
if (!wp_next_scheduled('disable_inactive_products_daily')) {
    wp_schedule_event(time(), 'daily', 'disable_inactive_products_daily');
}

// Привязываем функцию к событию
add_action('disable_inactive_products_daily', 'disable_inactive_products');

Этот код добавляет ежедневную задачу, которая отключает все товары без продаж за последние 90 дней.

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

  • Через админ-панель перейдите в Товары и отфильтруйте по статусу Черновик. Там должны появиться отключённые товары.
  • В базе данных в таблице wp_posts у товаров изменится поле post_status на draft.
  • Для отладки можно временно добавить логирование в функцию для вывода отключённых ID.

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

  • Отсутствие заказов с нужными статусами: если в магазине используются нестандартные статусы заказов, их нужно добавить в условие post_status IN ('wc-completed', 'wc-processing').
  • Проблемы с WP-Cron: если задачи не выполняются, убедитесь, что на сайте есть посещения или настройте системный cron для вызова wp-cron.php.
  • Неправильные префиксы таблиц: используйте $wpdb->prefix, а не жестко прописанный wp_.
  • Потеря товаров из-за неправильного периода: не ставьте слишком короткий период, чтобы не отключить активные товары.

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

  • Для больших каталогов запрос может быть тяжёлым. В таком случае разбивайте обработку на чанки, например, по 100 товаров.
  • Добавьте проверку прав пользователя, если функцию вызываете из интерфейса.
  • Перед массовым изменением статусов сделайте резервную копию базы данных.
  • Для высокой нагрузки используйте WP-CLI скрипт, который можно запускать из командной строки по расписанию, исключая ограничения веб-сервера.
  • Если хотите уведомлять админа, добавьте отправку email с отчётом о деактивированных товарах.

Сравнение вариантов реализации

МетодПлюсыМинусы
WP-Cron + SQL запросГибко, автоматично, не требует плагиновЗависит от посещаемости сайта, сложность запросов при большом каталоге
Плагин автоматизацииПростота настройки, интерфейс, поддержкаДополнительные ресурсы, возможные конфликты, лицензии
WP-CLI скриптВысокая производительность, удобство при больших объемахТребует доступа к серверу и навыков командной строки
×
-15%
на премиум плагин
Clearfy

Защитите сайт!

Включить Clearfy »