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

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

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

Проверьте, как работает ваш купон:

  • Перейдите в WooCommerce > Купоны;
  • Откройте интересующий купон;
  • В разделе "Ограничения использования" проверьте поле "Использование купона" — если там нет ограничений по количеству или пользователям, купон будет многократно применяться;
  • Проверьте, могут ли зарегистрированные пользователи применить купон несколько раз;

Если купон можно использовать неограниченное количество раз, это проблема для бизнеса.

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

WooCommerce не предлагает опцию «один купон — один пользователь» из коробки, но это можно исправить с помощью кастомного кода.

1. Добавляем проверку использования купона для текущего пользователя

В functions.php вашей дочерней темы или в кастомном плагине добавьте следующий код:

add_filter('woocommerce_coupon_is_valid', 'wpprotect_prevent_coupon_reuse', 10, 3);
function wpprotect_prevent_coupon_reuse($valid, $coupon, $discount) {
    if (!$valid) return false;

    $user_id = get_current_user_id();
    if (!$user_id) return $valid; // Ограничение для гостей можно настроить отдельно

    $coupon_code = $coupon->get_code();

    // Получаем заказы пользователя
    $args = array(
        'customer_id' => $user_id,
        'status' => array('wc-processing', 'wc-completed', 'wc-on-hold'),
        'limit' => -1
    );
    $orders = wc_get_orders($args);

    foreach ($orders as $order) {
        $used_coupons = $order->get_used_coupons();
        if (in_array($coupon_code, $used_coupons)) {
            // Купон уже использован этим пользователем
            return false;
        }
    }

    return $valid;
}

2. Сообщение об ошибке для пользователя

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

add_filter('woocommerce_coupon_error', 'wpprotect_coupon_used_message', 10, 3);
function wpprotect_coupon_used_message($err, $err_code, $coupon) {
    if ($err_code === 'coupon_already_used') {
        return 'Вы уже использовали этот купон ранее. Повторное использование запрещено.';
    }
    return $err;
}

Чтобы система выдавала ошибку coupon_already_used, нужно немного доработать логику в функции проверки:

add_filter('woocommerce_coupon_is_valid', 'wpprotect_prevent_coupon_reuse', 10, 3);
function wpprotect_prevent_coupon_reuse($valid, $coupon, $discount) {
    if (!$valid) return false;

    $user_id = get_current_user_id();
    if (!$user_id) return $valid;

    $coupon_code = $coupon->get_code();

    $args = array(
        'customer_id' => $user_id,
        'status' => array('wc-processing', 'wc-completed', 'wc-on-hold'),
        'limit' => -1
    );
    $orders = wc_get_orders($args);

    foreach ($orders as $order) {
        $used_coupons = $order->get_used_coupons();
        if (in_array($coupon_code, $used_coupons)) {
            wc_add_notice(__('Вы уже использовали этот купон ранее. Повторное использование запрещено.', 'woocommerce'), 'error');
            return false;
        }
    }

    return $valid;
}

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

Для тестирования:

  1. Зарегистрируйте тестового пользователя и авторизуйтесь;
  2. Примените купон при оформлении заказа, завершите заказ;
  3. Попробуйте применить тот же купон в новой корзине под тем же пользователем;
  4. Должно появиться сообщение об ошибке, и купон отклонится;
  5. Проверьте, что другой пользователь может применить купон (если это допустимо);
  6. Для гостей купон будет работать без ограничений, если не добавить отдельную проверку.

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

  • Купон не отклоняется при повторном использовании: Возможно, ваш фильтр подключен некорректно или конфликтует с другими плагинами. Проверьте приоритеты фильтров и отключите сторонние плагины для теста.
  • Сообщение об ошибке не появляется: Важно, чтобы функция wc_add_notice была вызвана при проверке купона. Убедитесь, что код вставлен именно так, как в примерах.
  • Купон запрещён даже при первом использовании: Проверьте, что $user_id корректно определяется, и что заказы действительно содержат купон. Для теста добавьте логирование внутри функции.
  • Проверка не работает для гостей: Гости не имеют ID пользователя, для них нужно реализовать отдельную логику, например, по IP или через сессии, что менее надёжно.

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

  • Используйте кэширование заказов для оптимизации запроса wc_get_orders, особенно на сайтах с большим количеством заказов.
  • Если у вас много заказов, ограничьте статусами и датами запрос, чтобы ускорить проверку.
  • Для повышения безопасности не позволяйте гостям использовать купоны без ограничений — рассмотрите регистрацию или двухфакторную авторизацию.
  • Рассмотрите интеграцию с Clearfy Pro для оптимизации WooCommerce и очистки лишних запросов — это ускорит проверку купонов и работу магазина (подробнее).

Альтернативные варианты реализации

МетодПреимуществаНедостатки
Код в functions.php (описанный выше)Бесплатно, гибко, кастомизация под задачиТребует поддержки, может конфликтовать с другими плагинами
Плагины ограничения использования купонов (например, Advanced Coupons)Простота установки, готовый функционал, поддержкаПлатные решения, ограниченная гибкость
Использование кастомных ролей и условийМожно тонко настроить под бизнес-процессыСложно в реализации, требует глубоких знаний