Сценарий простой: клиент выбирает самовывоз, но не оставляет важную информацию — номер точки, желаемое время, имя получателя, ориентир для курьера внутри ТЦ. Если это поле не контролировать на стороне checkout, менеджер потом добирает данные вручную, а заказы зависают в уточнениях.
В WooCommerce это лучше решать не через «попросить клиента», а через явную валидацию на этапе оформления заказа. Тогда поле будет обязательным только при нужном способе доставки, а для курьерской доставки останется необязательным.
Когда это действительно нужно
Такой сценарий часто встречается в магазинах с несколькими точками выдачи, в пунктах самовывоза внутри торговых центров и в локальной рознице, где без комментария заказ нельзя собрать корректно. Если у вас самовывоз — это просто «забрать на складе», поле может быть лишним. Но если менеджеру нужен хотя бы один уточняющий параметр, обязательная проверка экономит время.
Что именно будем делать
Ниже — вариант без сторонних плагинов: добавим поле комментария на checkout, сделаем его обязательным только при выборе самовывоза и сохраним значение в заказе. Логика будет завязана на стандартные хуки WooCommerce, без выдуманных API и без правки шаблонов темы.
Диагностика проблемы перед правкой
Сначала проверьте, как у вас называется способ доставки. В WooCommerce самовывоз обычно имеет идентификатор local_pickup, но в конкретной установке он может быть частью метода с индексом, например local_pickup:3. Это важно: если в коде сравнивать не тот ID, условие не сработает.
Откройте страницу оформления заказа и посмотрите, какой метод выбирается по умолчанию. Если самовывоз уже активен, поле должно стать обязательным сразу. Если клиент переключается между доставкой и самовывозом, лучше проверить, обновляется ли checkout через AJAX без перезагрузки.
- Проверьте, включён ли блок checkout в вашей теме или используется классический шаблон.
- Убедитесь, что поле комментария не дублируется другим плагином.
- Посмотрите, не скрывает ли кэш/оптимизатор скрипты WooCommerce на checkout.
- Проверьте, что в заказе сохраняется мета-данные, а не только визуальное значение в форме.
Пошаговое решение через код
Ниже пример для functions.php дочерней темы или для собственного мини-плагина. Я рекомендую именно мини-плагин: так код не потеряется при смене темы.
1. Добавляем поле на checkout
add_action( 'woocommerce_after_order_notes', function( $checkout ) {
woocommerce_form_field( 'pickup_comment', array(
'type' => 'textarea',
'class' => array( 'form-row-wide' ),
'label' => 'Комментарий для самовывоза',
'placeholder' => 'Например: заберу после 18:00, нужен звонок за 10 минут',
'required' => false,
), $checkout->get_value( 'pickup_comment' ) );
} );Поле пока необязательное. Обязательность зададим на этапе проверки, потому что она должна зависеть от выбранной доставки.
2. Проверяем выбранный способ доставки
add_action( 'woocommerce_checkout_process', function() {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_method = is_array( $chosen_methods ) && ! empty( $chosen_methods[0] ) ? $chosen_methods[0] : '';
if ( strpos( $chosen_method, 'local_pickup' ) !== false ) {
if ( empty( $_POST['pickup_comment'] ) ) {
wc_add_notice( 'Для самовывоза укажите комментарий к заказу.', 'error' );
}
}
} );Здесь используется проверка через strpos(), чтобы не зависеть от конкретного индекса метода. Это практичнее, чем жёстко сравнивать только local_pickup.
3. Сохраняем значение в заказе
add_action( 'woocommerce_checkout_create_order', function( $order, $data ) {
if ( ! empty( $_POST['pickup_comment'] ) ) {
$order->update_meta_data( '_pickup_comment', sanitize_textarea_field( wp_unslash( $_POST['pickup_comment'] ) ) );
}
}, 10, 2 );Санитизация обязательна. Даже если поле выглядит «обычным текстом», в заказ лучше сохранять уже очищенное значение.
4. Показываем комментарий в админке заказа
add_action( 'woocommerce_admin_order_data_after_billing_address', function( $order ) {
$comment = $order->get_meta( '_pickup_comment' );
if ( $comment ) {
echo '<p><strong>Комментарий для самовывоза:</strong> ' . esc_html( $comment ) . '</p>';
}
} );Так менеджер увидит комментарий прямо в карточке заказа, без поиска по метаполям.
Если нужен более гибкий вариант
Иногда поле должно появляться только при самовывозе и исчезать при других способах доставки без перезагрузки страницы. Тогда можно добавить небольшой JS, который будет переключать обязательность и видимость поля на лету. Это полезно, если checkout часто меняется и вы не хотите заставлять клиента отправлять форму с лишними ошибками.
add_action( 'wp_footer', function() {
if ( ! is_checkout() ) {
return;
}
?>
<script>
(function($){
function togglePickupComment() {
var method = $('input[name^="shipping_method"]:checked').val() || '';
var field = $('#pickup_comment_field');
var input = $('#pickup_comment');
if ( method.indexOf('local_pickup') !== -1 ) {
field.show();
input.attr('required', 'required');
} else {
field.hide();
input.removeAttr('required');
}
}
$(document.body).on('updated_checkout change', togglePickupComment);
$(togglePickupComment);
})(jQuery);
</script>
<?php
} );Этот вариант не заменяет серверную проверку. JS нужен только для удобства пользователя, а настоящая защита должна оставаться в woocommerce_checkout_process.
Сравнение подходов
| Подход | Плюсы | Минусы | Когда выбирать |
|---|---|---|---|
| Плагин для checkout-форм | Быстро, без кода | Лишняя зависимость, возможны конфликты с темой | Если нет доступа к разработке и нужна простая настройка |
| Код через хуки WooCommerce | Контроль логики, минимум лишнего | Нужно тестировать после обновлений | Если нужно точечное правило для самовывоза |
| Правка шаблона checkout | Полный контроль над версткой | Сложнее поддерживать, легко сломать обновлениями | Если форма сильно кастомизирована |
Как проверить, что решение сработало
После внедрения пройдите тестовый заказ в двух сценариях: с самовывозом и с курьерской доставкой. В первом случае пустое поле должно блокировать оформление и показывать понятную ошибку. Во втором — заказ должен проходить без обязательного комментария.
- Откройте checkout в режиме инкогнито, чтобы исключить влияние сохранённых сессий.
- Выберите самовывоз и отправьте форму без комментария.
- Проверьте, что WooCommerce показывает notice с ошибкой.
- Заполните поле и завершите заказ.
- Откройте заказ в админке и убедитесь, что комментарий сохранён в метаданных.
Если поле видно в форме, но заказ всё равно проходит без текста, значит серверная проверка не срабатывает. Обычно причина в неверном ID метода доставки или в том, что код вставлен не туда.
Частые ошибки и как их исправить
Проверяют только local_pickup, а метод имеет суффикс
В реальных магазинах метод доставки часто выглядит как local_pickup:1 или local_pickup:2. Если сравнение жёсткое, условие не выполнится. Используйте проверку через strpos() или сравнивайте с полным ID, который реально возвращает checkout.
Ставят обязательность только через HTML-атрибут required
Это не защита. Пользователь может обойти её, отключить JS или отправить форму нестандартным способом. Обязательная проверка должна быть на сервере, в woocommerce_checkout_process.
Сохраняют значение без санитизации
Если записывать $_POST напрямую, в заказ может попасть мусор или лишняя разметка. Для textarea используйте sanitize_textarea_field() и wp_unslash().
Не проверяют конфликт с плагинами checkout
Плагины для кастомизации оформления заказа могут переименовывать поля, менять структуру формы или отключать стандартные хуки. Если код не работает, временно отключите такие плагины и проверьте базовый сценарий на стандартной теме.
Что учесть по безопасности и производительности
Это небольшая доработка, но и здесь есть практические моменты. Не вставляйте код в произвольный плагин с автогенерацией сниппетов, если не понимаете, как он хранит и исполняет PHP. Лучше использовать собственный мини-плагин или дочернюю тему. Так проще контролировать версию и откатывать изменения.
Если на checkout уже много скриптов, не добавляйте лишний JavaScript без необходимости. В большинстве случаев серверной проверки достаточно, а JS нужен только для UX. И ещё: не отключайте стандартные скрипты WooCommerce на странице оформления заказа, иначе AJAX-обновление доставки может перестать работать.
Если вам нужно не только обязательное поле, но и более сложная логика checkout — например, разные поля для разных зон доставки или автоматические уведомления менеджеру — лучше сразу закладывать это в отдельный мини-плагин. Так код не расползётся по теме и не потеряется при обновлении шаблона.