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

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

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

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

Что нужно учесть перед реализацией

  • Убедитесь, что учет запасов включен для вариаций (Manage stock = true).
  • Определитесь с периодом, за который считать продажи (например, 30 дней).
  • Резервное копирование базы данных перед внесением изменений.

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

Для автоматического отключения вариантов с нулевым остатком и отсутствием продаж за последние 30 дней добавим кастомную функцию на cron или вызов вручную.

function wc_disable_inactive_variations() {
    $args = array(
        'post_type' => 'product_variation',
        'posts_per_page' => -1,
        'post_status' => 'publish',
        'meta_query' => array(
            array(
                'key' => '_stock_status',
                'value' => 'outofstock'
            ),
            array(
                'key' => '_manage_stock',
                'value' => 'yes'
            )
        )
    );
    $variations = get_posts($args);
    $threshold_date = strtotime('-30 days');

    foreach ($variations as $variation) {
        $variation_id = $variation->ID;

        // Получаем количество продаж вариации за последние 30 дней
        global $wpdb;
        $sales_count = $wpdb->get_var($wpdb->prepare(
            "SELECT SUM(oi.meta_value) FROM {$wpdb->prefix}woocommerce_order_items AS oi
            LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS oim ON oi.order_item_id = oim.order_item_id
            LEFT JOIN {$wpdb->prefix}posts AS p ON p.ID = oi.order_id
            WHERE oi.order_item_type = 'line_item'
            AND oim.meta_key = '_variation_id'
            AND oim.meta_value = %d
            AND p.post_type = 'shop_order'
            AND p.post_status IN ('wc-completed', 'wc-processing', 'wc-on-hold')
            AND p.post_date >= %s
            AND oi.order_item_id = oi.order_item_id
            AND EXISTS (
                SELECT 1 FROM {$wpdb->prefix}woocommerce_order_itemmeta AS qty_meta
                WHERE qty_meta.order_item_id = oi.order_item_id
                AND qty_meta.meta_key = '_qty'
            )",
            $variation_id,
            date('Y-m-d H:i:s', $threshold_date)
        ));

        $sales_count = intval($sales_count);

        if ($sales_count === 0) {
            // Отключаем вариант
            wp_update_post(array(
                'ID' => $variation_id,
                'post_status' => 'draft'
            ));
        }
    }
}

// Пример вызова функции вручную или через WP-Cron
// wc_disable_inactive_variations();

Как добавить запуск функции по расписанию

Добавьте в functions.php или в плагин следующее для ежедневного запуска:

if (!wp_next_scheduled('wc_disable_inactive_variations_daily')) {
    wp_schedule_event(time(), 'daily', 'wc_disable_inactive_variations_daily');
}
add_action('wc_disable_inactive_variations_daily', 'wc_disable_inactive_variations');

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

  • Перейдите в раздел «Вариации» нужного товара и убедитесь, что варианты с нулевым остатком и без продаж стали со статусом «Черновик» (draft) и не отображаются на сайте.
  • Проверьте логи cron, если используете планировщик, или вызовите функцию вручную и убедитесь в отсутствии ошибок.
  • Для теста создайте вариацию с нулевым остатком и без продаж, запустите функцию и проверьте её статус.

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

  • Неправильный статус вариации после обновления. Причина: функция использует wp_update_post с неверным статусом. Проверьте, что используете post_status => 'draft' для скрытия вариации.
  • Функция не находит вариации. Убедитесь, что в базе вариации имеют статус publish и метаполя _stock_status = outofstock, а также _manage_stock = yes.
  • Неверный подсчет продаж. В SQL-запросе учитываются только статусы заказов wc-completed, wc-processing, wc-on-hold. Измените список при необходимости.
  • Функция не запускается по расписанию. Проверьте активность WP-Cron, его логи и наличие планировщика задач на сервере.

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

  • Перед массовыми изменениями всегда делайте резервную копию базы.
  • Для сайтов с большим количеством вариаций делайте обработку частями (например, по 100 штук за один запуск) чтобы не перегружать сервер.
  • Используйте WP-CLI для запуска скриптов вручную или в cron, это надежнее чем WP-Cron на слабых хостингах.
  • Добавьте проверку nonce и прав пользователя, если планируете запускать функцию через админку.
  • Кэшируйте результаты запроса продаж, если запускаете часто, чтобы снизить нагрузку на базу.

Сравнение способов решения задачи

МетодПреимуществаНедостатки
Ручное отключение вариацийПростота, не требует кодаТрудозатратно, риск ошибок при большом количестве товаров
Плагин для управления запасамиГотовое решение, поддержкаМожет быть платным, дополнительные зависимости
Кастомный скрипт на PHP (как в статье)Полный контроль, бесплатное решение, легко адаптироватьТребует навыков разработки, ответственность за тестирование
Как создать динамическое меню в WordPress: пошаговое руководство
21.11.2025
Как удалить автоматические редиректы в WordPress: практическое руководство
29.01.2026
Как добавить AJAX фильтрацию товаров в WordPress без перезагрузки страницы
25.01.2026
Автоматическое удаление старых черновиков и постов в WordPress
09.03.2026
WooCommerce: как использовать WC REST API для автоматизации управления заказами
24.05.2026