Сценарий типичный: на десктопе оформление заказа проходит нормально, а на телефоне пользователь заполняет имя, телефон, адрес — и часть полей после обновления блока checkout оказывается пустой. Иногда проблема проявляется только в мобильной теме, иногда только при включенном кэше, а иногда после установки плагина для оптимизации скриптов.
В WooCommerce это обычно не «сломанная форма», а конфликт между AJAX-обновлением checkout, кэшированием, сторонними масками телефона и скриптами, которые вмешиваются в события change и updated_checkout. Ниже — рабочий порядок проверки и исправления.
Как понять, где именно ломается сохранение полей
Сначала важно отделить проблему фронтенда от проблемы сохранения заказа на сервере. Если поле визуально очищается после пересчета доставки или выбора способа оплаты, это почти всегда фронтенд-слой. Если значение видно в форме, но не попадает в заказ, нужно смотреть хуки сохранения и кастомные поля.
Что проверить в первую очередь
- Открывается ли checkout без ошибок JavaScript в консоли браузера.
- Не включен ли плагин минификации, который объединяет или откладывает
checkout.js. - Не кэшируется ли страница оформления заказа на уровне плагина, CDN или сервера.
- Не добавляет ли тема или плагин собственную маску телефона, автозаполнение или валидацию.
- Не обновляется ли блок checkout после выбора доставки, из-за чего сторонний скрипт сбрасывает значения.
Если есть доступ к DevTools на мобильном устройстве через удаленную отладку, откройте вкладку Console и посмотрите, нет ли ошибок вида Uncaught TypeError, $ is not a function или Cannot read properties of undefined. Даже одна такая ошибка может остановить обработчик WooCommerce.
Почему это происходит именно на мобильных
На мобильных сайтах чаще включают агрессивную оптимизацию: отложенную загрузку JS, объединение файлов, lazy-load для всего подряд, а иногда и отдельную мобильную версию темы. В checkout это опасно, потому что WooCommerce опирается на последовательность событий и на повторную инициализацию полей после AJAX-обновления.
Еще один частый источник проблемы — скрипты маски телефона. Они могут перезаписывать значение поля при каждом input или blur, а после AJAX-перерисовки checkout не переинициализируются. На десктопе это не всегда заметно, потому что пользователь вводит данные быстрее и форма реже перерисовывается.
| Подход | Когда подходит | Минус |
|---|---|---|
| Отключить оптимизацию JS для checkout | Если ошибка появилась после ускорения сайта | Чуть меньше выигрыш по скорости на одной странице |
| Исправить конфликт в теме/плагине | Если проблема только с конкретным полем | Нужно искать источник по одному |
| Добавить защитное сохранение значений через хуки | Если поле сбрасывается после AJAX-обновления | Не лечит сломанный сторонний скрипт, только последствия |
Пошаговое решение
1. Исключите checkout из кэширования и оптимизации
Страница оформления заказа не должна попадать под кэш HTML. Для большинства кэш-плагинов это настраивается исключением URL /checkout/, /cart/ и /my-account/. Если используется серверный кэш или CDN, проверьте, что для checkout не включено кеширование HTML и не подставляется stale-версия страницы.
Если у вас есть плагин оптимизации, временно отключите для checkout:
- объединение JS;
- отложенную загрузку JavaScript;
- defer/async для скриптов WooCommerce;
- lazy-load для inline-скриптов формы.
На практике этого часто достаточно, если проблема появилась после «ускорения» сайта.
2. Проверьте, не сбрасывает ли поле сторонний скрипт
Если вы используете маску телефона или автозаполнение адреса, временно отключите их и проверьте checkout на мобильном. Если проблема исчезла, нужно не удалять весь плагин, а ограничить его работу только на нужных полях и переинициализировать после события updated_checkout.
Пример безопасной переинициализации для собственного скрипта:
jQuery(function($) {
function initPhoneMask() {
var $phone = $('#billing_phone');
if (!$phone.length) {
return;
}
if ($phone.data('mask-initialized')) {
return;
}
// Здесь должен быть вызов вашей реальной библиотеки маски.
// Например, IMask или Inputmask, если они уже подключены темой/плагином.
$phone.data('mask-initialized', true);
}
initPhoneMask();
$(document.body).on('updated_checkout', function() {
$('#billing_phone').removeData('mask-initialized');
initPhoneMask();
});
});Смысл здесь простой: после AJAX-обновления WooCommerce DOM может перерисоваться, и старые обработчики уже не работают. Если ваш скрипт не умеет переживать перерисовку, поля будут вести себя нестабильно.
3. Сохраните значения полей через хуки WooCommerce
Если проблема в том, что пользователь видит заполненное поле, но после обновления checkout значение теряется, можно подстраховать сохранение через сессию WooCommerce. Это не заменяет исправление фронтенда, но помогает не терять данные при повторной отрисовке.
add_action('woocommerce_checkout_update_order_review', function($post_data) {
if (!function_exists('WC') || !WC()->session) {
return;
}
parse_str($post_data, $data);
$fields = array(
'billing_phone',
'billing_first_name',
'billing_last_name',
'billing_address_1',
'billing_city',
'billing_postcode',
);
foreach ($fields as $field) {
if (isset($data[$field])) {
WC()->session->set($field, sanitize_text_field(wp_unslash($data[$field])));
}
}
});
add_filter('woocommerce_checkout_get_value', function($value, $input) {
if ($value !== '') {
return $value;
}
if (function_exists('WC') && WC()->session) {
$saved = WC()->session->get($input);
if ($saved !== null) {
return $saved;
}
}
return $value;
}, 10, 2);Этот код полезен, когда checkout перерисовывается из-за доставки, купона или смены способа оплаты. Но если у вас есть конфликтующий JS, его все равно нужно убрать, иначе вы просто замаскируете симптом.
4. Если поле кастомное, проверьте его сохранение в заказ
Иногда проблема не в стандартных полях WooCommerce, а в дополнительном поле, которое добавили через тему или плагин. Тогда нужно отдельно сохранить его в метаданных заказа.
add_action('woocommerce_checkout_create_order', function($order, $data) {
if (!empty($_POST['delivery_comment'])) {
$order->update_meta_data(
'_delivery_comment',
sanitize_textarea_field(wp_unslash($_POST['delivery_comment']))
);
}
}, 10, 2);Если поле есть в форме, но отсутствует в заказе, проверьте три вещи: правильный name у input, наличие nonce/валидации и отсутствие JavaScript, который подменяет значение перед отправкой.
Проверка результата после внедрения
После правок не ограничивайтесь одним тестом на десктопе. Нужна проверка именно на мобильном сценарии, потому что проблема часто проявляется только после смены доставки или при повторной отрисовке блока checkout.
- Откройте checkout на телефоне или в эмуляторе.
- Заполните телефон, имя и адрес.
- Смените способ доставки или примените купон, чтобы вызвать AJAX-обновление.
- Убедитесь, что значения не сбросились.
- Дойдите до создания заказа и проверьте, что данные попали в карточку заказа в админке.
Если используете логирование, можно временно включить запись в wp-content/debug.log и посмотреть, не падает ли какой-то скрипт или PHP-обработчик. Для этого в wp-config.php обычно включают:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);После проверки не забудьте вернуть отладку в штатный режим, если сайт рабочий и лог не нужен постоянно.
Частые ошибки и как их исправить
Поле очищается только после выбора доставки
Причина почти всегда в том, что сторонний скрипт не переживает событие updated_checkout. Решение — переинициализировать маску или автозаполнение после каждого AJAX-обновления.
На мобильном все ломается, на десктопе нет
Часто виноват не сам WooCommerce, а мобильная оптимизация: defer для всех скриптов, агрессивная минификация или мобильный плагин темы. Проверьте, не отличается ли набор подключаемых файлов на мобильных устройствах.
Значение видно в форме, но не сохраняется в заказе
Это уже серверная часть: либо поле не передается в POST, либо не сохранено в метаданные заказа. Сначала проверьте имя поля и наличие данных в $_POST, потом — хук woocommerce_checkout_create_order.
Проблема исчезает после отключения кэша
Значит, checkout кэшируется там, где не должен. Не пытайтесь лечить это кодом в шаблоне — сначала исключите checkout из кэширования на уровне плагина, сервера и CDN.
Практические советы по безопасности и производительности
Если вы добавляете собственные хуки, не сохраняйте сырые данные из $_POST. Для текстовых полей используйте sanitize_text_field(), для многострочных — sanitize_textarea_field(). Это не только вопрос безопасности, но и способ избежать мусора в заказах.
Не держите в checkout лишние скрипты. Чем больше сторонних библиотек на странице оформления заказа, тем выше шанс конфликта. Если плагин нужен только на одной странице, подключайте его условно через is_checkout().
Если проблема возникла после установки плагина оптимизации, не отключайте его целиком на всем сайте. Обычно достаточно исключить только checkout и cart. Это сохраняет выигрыш по скорости на остальных страницах и не ломает оформление заказа.
Для сайтов, где много нестандартных блоков и дублей в шаблонах, полезно периодически проверять фронтенд и лишние обертки. В таких задачах иногда выручает Clearfy Pro, если нужен аккуратный контроль над дублями и частью служебных настроек, но саму проблему checkout он не исправит без точечной диагностики.
Если после всех правок ошибка остается, сравните поведение на чистой теме и с отключенными сторонними плагинами. Это самый быстрый способ понять, где искать источник: в теме, в оптимизации или в конкретном расширении WooCommerce.