Проблема: как ограничить доступ к платёжным методам после неудачного платежа
В интернет-магазинах на WooCommerce часто возникает необходимость блокировать или скрывать определённые платёжные методы для пользователей, у которых была зафиксирована неудачная попытка оплаты. Это помогает избежать повторных ошибок и перегрузки платёжной системы, а также мотивирует клиентов связаться с поддержкой. Решение должно работать автоматически, без ручного вмешательства администратора.
Диагностика проблемы
Для начала убедитесь, что у вас корректно фиксируются статусы заказов, особенно статусы, обозначающие неудачные платежи (например, 'failed', 'cancelled', 'pending'). Проверьте, что WooCommerce отправляет эти статусы и что они доступны для программной обработки.
Для диагностики используйте следующий код, который выведет статус последнего заказа пользователя:
add_action('wp_footer', function() {
if (is_user_logged_in()) {
$user_id = get_current_user_id();
$orders = wc_get_orders(array(
'customer_id' => $user_id,
'limit' => 1,
'orderby' => 'date',
'order' => 'DESC',
));
if (!empty($orders)) {
$last_order = $orders[0];
echo '<div style="position:fixed;bottom:0;right:0;background:#fff;padding:10px;border:1px solid #ccc;z-index:9999;">';
echo 'Последний заказ: #'. $last_order->get_id() .', статус: '. $last_order->get_status();
echo '</div>';
}
}
});Если вы видите внизу страницы статус последнего заказа, значит данные доступны, можно двигаться дальше.
Пошаговое решение: блокировка платёжных методов по статусу последнего заказа
Отфильтруем платёжные методы в зависимости от статуса последнего заказа пользователя. В примере ниже платёжные методы будут отключены, если статус последнего заказа пользователя — failed или cancelled.
add_filter('woocommerce_available_payment_gateways', function($gateways) {
if (!is_user_logged_in()) {
return $gateways; // для гостей не меняем
}
$user_id = get_current_user_id();
$orders = wc_get_orders(array(
'customer_id' => $user_id,
'limit' => 1,
'orderby' => 'date',
'order' => 'DESC',
));
if (empty($orders)) {
return $gateways; // заказов нет, ничего не меняем
}
$last_order = $orders[0];
$status = $last_order->get_status();
if (in_array($status, array('failed', 'cancelled'))) {
// отключаем все платёжные методы кроме, например, 'cod' (наложенный платеж)
foreach ($gateways as $key => $gateway) {
if ($key !== 'cod') {
unset($gateways[$key]);
}
}
}
return $gateways;
});В этом примере разрешён только метод 'cod'. Вы можете заменить или дополнить список разрешённых методов по своему усмотрению.
Как адаптировать под свои задачи
- Измените массив статусов в
in_arrayсогласно вашим бизнес-требованиям. - Настройте список разрешённых методов, перечислив их ключи в условии.
- Добавьте логику сброса блокировки после успешного платежа с помощью хука
woocommerce_order_status_completed.
Проверка результата после внедрения
- Авторизуйтесь под пользователем с неудачным заказом (статус failed или cancelled).
- Перейдите в корзину и оформите заказ.
- Убедитесь, что в списке платёжных методов отображается только разрешённый (например, наложенный платеж).
- Войдите под пользователем без неудачных заказов — все платёжные методы должны быть доступны.
Частые ошибки и как исправить
- Платёжные методы не меняются: проверьте, что фильтр
woocommerce_available_payment_gatewaysподключён в файлеfunctions.phpвашей темы или в плагине. Также проверьте, что статусы заказов действительно меняются наfailedилиcancelled. - Ошибка с отсутствием функций: убедитесь, что WooCommerce активен и функция
wc_get_ordersдоступна. - Платёжный метод не отключается полностью: некоторые плагины платёжных систем могут кэшировать методы, проверьте, нет ли кэширования на уровне сайта или сервера.
- Не работает для гостей: по умолчанию фильтр не применён для неавторизованных пользователей. Если надо — добавьте логику по IP или сессии.
Практические советы по безопасности и производительности
- Для снижения нагрузки используйте кеширование результатов запроса
wc_get_orders, например, в transients с небольшим TTL. - Обязательно тестируйте на тестовом стенде, чтобы избежать блокировок платежей для корректных пользователей.
- Не храните вручную статус блокировки — используйте данные из заказов, чтобы избежать рассинхронизации.
- Для дополнительной безопасности ограничьте доступ к платёжным методам только после подтверждения статуса заказа через вебхуки платёжных систем.
Сравнение способов реализации
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
Фильтр woocommerce_available_payment_gateways |
Код в functions.php, проверка статуса последнего заказа | Быстро, гибко, без сторонних плагинов | Требует знаний PHP, может вызвать конфликты с плагинами |
| Сторонние плагины для управления платёжными методами | Плагины с GUI для настройки ограничений | Удобно для непрофессионалов, поддержка | Может замедлить сайт, ограничения в гибкости |
| Кастомное расширение WooCommerce | Разработка полноценного плагина с кастомной логикой | Максимальная гибкость, масштабируемость | Требует времени и навыков, сложность поддержки |