Диагностика проблемы: зачем отключать оплату для товаров с определённым статусом
В WooCommerce нередко возникает задача сделать товары с определённым статусом (например, "в ожидании", "черновик", "тестовый" или пользовательский статус) недоступными для оплаты, но при этом оставить их видимыми в каталоге. Это может понадобиться, если товар временно не продаётся, но его нужно оставить на сайте для показа или тестирования.
Как понять, что стандартных настроек WooCommerce недостаточно
В стандартном WooCommerce нет возможности напрямую запретить оплату для товаров по статусу. Можно скрыть товар (через видимость), но это удалит товар из каталога. Плагинов с точечной функцией обычно нет, и универсальные решения требуют кастомизации.
Пошаговое решение: отключение оплаты для товаров с определённым статусом
1. Добавление пользовательского статуса товара (если нужно)
Если у вас нет готового статуса, добавим пользовательский статус 'waiting_payment' для товаров. Добавьте код в functions.php вашей темы или в плагин для кастомизации:
function register_product_custom_status() {
register_post_status( 'wc-waiting_payment', array(
'label' => _x( 'Waiting Payment', 'Product status', 'woocommerce' ),
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'Waiting Payment <span class="count">(%s)</span>', 'Waiting Payment <span class="count">(%s)</span>', 'woocommerce' ),
) );
}
add_action( 'init', 'register_product_custom_status' );2. Запрет оплаты для товаров с этим статусом
Добавим фильтр, который проверит содержимое корзины и заблокирует оформление заказа, если в корзине есть товары с заданным статусом.
function wc_disable_checkout_if_product_status_pending( $valid ) {
if ( ! $valid ) {
return false;
}
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$status = get_post_status( $product->get_id() );
if ( $status === 'wc-waiting_payment' ) {
wc_add_notice( 'Оплата отключена для некоторых товаров в корзине.', 'error' );
return false;
}
}
return $valid;
}
add_filter( 'woocommerce_checkout_process', 'wc_disable_checkout_if_product_status_pending' );3. Скрытие кнопки «Купить» на страницах товаров с этим статусом
Чтобы пользователь не мог добавить товар с таким статусом в корзину, скроем кнопку «Добавить в корзину» для таких товаров:
function wc_hide_add_to_cart_button_for_custom_status() {
global $product;
if ( ! $product ) {
return;
}
$status = get_post_status( $product->get_id() );
if ( $status === 'wc-waiting_payment' ) {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
}
}
add_action( 'woocommerce_before_single_product', 'wc_hide_add_to_cart_button_for_custom_status' );Проверка результата после внедрения
- Создайте товар с пользовательским статусом
wc-waiting_payment. - Зайдите на страницу товара — кнопка "Добавить в корзину" должна отсутствовать.
- Если товар каким-то образом окажется в корзине (например, через прямой запрос), при попытке оформления заказа должно появиться сообщение об ошибке и процесс должен прерваться.
- Для товаров с другими статусами оплата должна работать штатно.
Частые ошибки и их исправление
- Ошибка: Товар с нужным статусом по-прежнему можно добавить в корзину.
Причина: Не сработал хук удаления кнопки или статус указан неверно.
Решение: Проверьте правильность регистраций статусов и используйтеerror_logдля отладкиget_post_status(). - Ошибка: Сообщение об ошибке на оформлении заказа не появляется.
Причина: Фильтрwoocommerce_checkout_processне возвращает false.
Решение: Убедитесь, что функция возвращает false при обнаружении запрещённых товаров. - Ошибка: Пользователь видит кнопку, но при клике ничего не происходит.
Причина: Кнопка не удалена, а только скрыта стилями.
Решение: Используйтеremove_action()для удаления кнопки, а не CSS-стили.
Практические советы по безопасности и производительности
- Регистрация пользовательских статусов должна происходить на
initс приоритетом по умолчанию. - Проверка статуса товара в корзине выполняется по ID продукта — это эффективно и не создаёт дополнительных запросов.
- Для крупных магазинов с большим количеством товаров стоит дополнительно кэшировать статусы, чтобы снизить нагрузку.
- Проверяйте совместимость с плагинами кеширования: сообщения об ошибках лучше выводить через
wc_add_notice.
Сравнение вариантов реализации
| Вариант | Плюсы | Минусы | Применимость |
|---|---|---|---|
| Код в functions.php (описанный выше) | Полный контроль, отсутствие лишних плагинов, точечное решение | Требует базовых знаний PHP, поддержка на разработчике | Лучший вариант для кастомных проектов |
| Плагины ограничения покупки (например, "WooCommerce Catalog Mode") | Простая настройка, UI для управления | Часто общий режим каталога, нет гибкой фильтрации по статусу | Подойдёт для простых случаев без кастомных статусов |
| Использование видимости товара WooCommerce | Встроенный функционал, простой в использовании | Товар скрывается из каталога, нельзя просто отключить оплату | Если нужно скрыть товар полностью |