Диагностика проблемы: почему нужно блокировать оплату
В интернет-магазинах на WooCommerce часто возникает задача запретить оформление заказа, если в корзине присутствуют товары с определёнными атрибутами. Например, товары с ограниченной доступностью, товары, требующие дополнительных согласований, или товары с нестандартными условиями продажи.
Без блокировки пользователь может оформить заказ, который магазин не готов обработать, что приводит к ошибкам, возвратам и негативному опыту.
Как определить наличие товаров с нужными атрибутами в корзине
WooCommerce хранит товары в корзине с объектами WC_Cart_Item. У каждого товара можно проверить атрибуты через свойства товара.
function has_product_with_attribute( $attribute_name, $attribute_value ) {
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$attributes = $product->get_attributes();
foreach ( $attributes as $attr ) {
if ( $attr->is_taxonomy() ) {
$terms = wp_get_post_terms( $product->get_id(), $attr->get_name(), array('fields' => 'names') );
if ( in_array( $attribute_value, $terms, true ) ) {
return true;
}
} else {
if ( $attr->get_options() && in_array( $attribute_value, $attr->get_options(), true ) ) {
return true;
}
}
}
}
return false;
}Этот код проверяет, есть ли в корзине товар с заданным атрибутом и значением.
Пошаговое решение: блокируем кнопку оплаты
1. Добавляем проверку в хук woocommerce_checkout_process, чтобы прервать оформление при наличии запрещённых товаров.
2. Выводим сообщение пользователю о причине блокировки.
add_action( 'woocommerce_checkout_process', 'block_checkout_if_attribute_in_cart' );
function block_checkout_if_attribute_in_cart() {
$attribute_name = 'pa_special'; // замените на свой slug атрибута
$attribute_value = 'restricted'; // значение атрибута, при котором блокируем
if ( has_product_with_attribute( $attribute_name, $attribute_value ) ) {
wc_add_notice( 'Оплата заблокирована: в корзине есть товары с ограниченной продажей.', 'error' );
}
}3. Для улучшения UX можно скрыть кнопку оплаты на странице корзины с помощью фильтра woocommerce_proceed_to_checkout или через JavaScript.
add_filter( 'woocommerce_proceed_to_checkout', 'disable_checkout_button_if_attribute' );
function disable_checkout_button_if_attribute( $button_html ) {
$attribute_name = 'pa_special';
$attribute_value = 'restricted';
if ( has_product_with_attribute( $attribute_name, $attribute_value ) ) {
return '<p class="woocommerce-error">Оплата временно недоступна из-за ограничений по товарам в корзине.</p>';
}
return $button_html;
}Проверка результата после внедрения
- Добавьте в корзину товар с нужным атрибутом.
- Перейдите на страницу оформления заказа – должна появиться ошибка, а оформление блокироваться.
- На странице корзины кнопка оплаты должна быть заменена на предупреждение.
- Для теста положите в корзину товар без атрибута – оформление и кнопка должны работать.
Частые ошибки и их исправление
- Неверный slug атрибута: В WooCommerce атрибуты товаров имеют префикс
pa_. Проверьте правильность названия. - Атрибут задан не как таксономия: Если атрибут не зарегистрирован глобально, используйте другие методы для получения значения.
- Кэширование корзины: Некоторые сайты с кэшированием могут не обновлять состояние кнопок. Отключите кэширование страниц корзины и оформления.
- Ошибка в функции проверки: Убедитесь, что функция
has_product_with_attributeподключена и доступна в текущем контексте.
Практические советы по безопасности и производительности
- Используйте хук
woocommerce_checkout_processдля серверной проверки, чтобы нельзя было обойти блокировку через клиентский код. - Минимизируйте количество запросов к базе, кэшируя результаты проверки при вызове в рамках одного запроса.
- Добавьте клиентскую проверку (на JS), чтобы пользователь сразу видел ограничение без повторного запроса.
- Не выводите подробности об ошибках, которые могут раскрыть структуру магазина или бизнес-логику.
Сравнение вариантов реализации блокировки оплаты
| Метод | Плюсы | Минусы | Пример использования |
|---|---|---|---|
Серверная проверка в woocommerce_checkout_process |
Надёжная, нельзя обойти, информирует на этапе оформления | Пользователь узнаёт об ошибке поздно | Пример кода выше |
| Клиентская проверка (JS) | Мгновенный фидбек, улучшенный UX | Можно обойти, нужен серверный контроль | Скрытие кнопки, показ уведомления |
| Плагин для условий корзины | Готовое решение, гибкие настройки без кода | Может нагружать сайт, ограничена кастомизация | WooCommerce Conditional Shipping and Payments |