Проблема: платежные системы остаются активными при неоплате заказа
В интернет-магазинах на WooCommerce часто возникает ситуация, когда покупатель создаёт заказ, но не завершает оплату. В результате доступные способы оплаты остаются активными, что может привести к путанице и лишней нагрузке на систему. Автоматическое отключение платежных систем для неоплаченных заказов помогает избежать этой проблемы, улучшить UX и снизить риск ошибок.
Диагностика проблемы
Для начала нужно понять, что WooCommerce по умолчанию не блокирует способы оплаты для неоплаченных заказов. Проверьте следующее:
- В разделе
WooCommerce > Настройки > Платежиактивированы все нужные способы оплаты. - При создании заказа, который не был оплачен, способы оплаты продолжают отображаться.
- Отсутствует логика, ограничивающая доступ к платежным методам в зависимости от статуса заказа.
Если задача — ограничить оплату только для новых заказов и отключать способы оплаты для неоплаченных со временем, потребуется кастомное решение.
Пошаговое решение: реализация автоматического отключения платежных систем
Шаг 1. Добавляем проверку статуса заказа и времени создания
Нам нужно фильтровать доступные способы оплаты на странице оформления заказа, отключая их, если есть неоплаченный заказ старше определённого времени (например, 1 час).
add_filter('woocommerce_available_payment_gateways', 'disable_payment_gateways_for_unpaid_orders');
function disable_payment_gateways_for_unpaid_orders($available_gateways) {
if (is_admin()) return $available_gateways; // Не менять в админке
$user_id = get_current_user_id();
if (!$user_id) return $available_gateways; // Только для залогиненных
$args = array(
'customer_id' => $user_id,
'status' => array('pending', 'on-hold'), // Неоплаченные статусы
'limit' => 1,
'orderby' => 'date',
'order' => 'ASC',
);
$orders = wc_get_orders($args);
if (empty($orders)) return $available_gateways; // Нет неоплаченных заказов
$order = $orders[0];
$order_date = $order->get_date_created();
if (!$order_date) return $available_gateways;
$order_timestamp = $order_date->getTimestamp();
$current_timestamp = current_time('timestamp');
$limit_seconds = 3600; // 1 час
if (($current_timestamp - $order_timestamp) > $limit_seconds) {
// Отключаем все способы оплаты
return array();
}
return $available_gateways;
}
Шаг 2. Вывод сообщения для пользователя
Если способы оплаты отключены, лучше уведомить пользователя, чтобы он понимал причину.
add_action('woocommerce_checkout_before_customer_details', 'show_payment_disabled_notice');
function show_payment_disabled_notice() {
$user_id = get_current_user_id();
if (!$user_id) return;
$args = array(
'customer_id' => $user_id,
'status' => array('pending', 'on-hold'),
'limit' => 1,
'orderby' => 'date',
'order' => 'ASC',
);
$orders = wc_get_orders($args);
if (empty($orders)) return;
$order = $orders[0];
$order_date = $order->get_date_created();
if (!$order_date) return;
$order_timestamp = $order_date->getTimestamp();
$current_timestamp = current_time('timestamp');
$limit_seconds = 3600;
if (($current_timestamp - $order_timestamp) > $limit_seconds) {
wc_print_notice('У вас есть неоплаченный заказ старше 1 часа. Оплата временно недоступна.', 'error');
}
}
Проверка результата после внедрения
- Создайте заказ с текущим пользователем и не оплачивайте его.
- Дождитесь истечения времени (например, 1 час) или временно уменьшите
$limit_secondsдля теста. - Перейдите на страницу оформления заказа. Способы оплаты должны быть отключены, и появится уведомление.
- Проверьте, что при отсутствии неоплаченных заказов способы оплаты отображаются корректно.
Частые ошибки и как исправить
- Платежи не отключаются: Проверьте, что пользователя идентифицируете правильно и что статус заказа действительно
pendingилиon-hold. - Способы оплаты отключаются для всех пользователей: Убедитесь, что проверка
get_current_user_id()работает корректно и что код не применяется в админке. - Сообщение не выводится: Проверьте, что хук
woocommerce_checkout_before_customer_detailsне конфликтует с другими плагинами и что функция вызывается. - Проблемы с часовым поясом: Для корректного подсчёта времени используйте
current_time('timestamp'), а неtime().
Практические советы по безопасности и производительности
- Оптимизируйте запросы
wc_get_orders, ограничивая выборку только необходимыми полями через параметр'return' => 'ids'при необходимости. - Используйте транзиенты для кэширования результатов проверки, если на сайте много пользователей, чтобы снизить нагрузку на базу.
- Не отключайте способы оплаты полностью, если это критично для бизнеса — лучше показать ограниченное сообщение или предложить связаться с поддержкой.
Сравнение вариантов реализации
| Метод | Плюсы | Минусы |
|---|---|---|
| Код в functions.php | Полный контроль, бесплатно, быстро | Требует навыков, требует тестирования |
| Плагины управления оплатой (например, WooCommerce Conditional Shipping and Payments) | Готовое решение, поддержка, GUI | Платно, может быть избыточным |
| Кастомные плагины | Гибкость, масштабируемость | Требует разработки и поддержки |