Сценарий типичный: форма Contact Form 7 отправилась успешно, письмо ушло, но интерфейс ведёт себя неудобно. Модальное окно не закрывается, поля остаются заполненными, кнопка продолжает крутиться, а пользователь не понимает, сработала ли отправка. На стороне WordPress это обычно не ошибка плагина, а конфликт между разметкой, скриптами темы и вашим JS-кодом.
Ниже разберём, как диагностировать проблему, какие события Contact Form 7 использовать, как закрывать форму и сбрасывать поля без перезагрузки страницы, и как проверить, что решение не ломает повторную отправку.
Когда проблема действительно в поведении формы
Сначала стоит отделить баг интерфейса от ошибки отправки. Если в админке Contact Form 7 вы видите статус успешной отправки, а письмо приходит, значит серверная часть работает. Проблема находится на фронтенде: форма не скрывается, модалка не закрывается, а поля не очищаются после события отправки.
Чаще всего это проявляется в таких сценариях:
- форма встроена в модальное окно и после успеха должна закрываться автоматически;
- форма находится в блоке с AJAX-подгрузкой и после отправки остаётся в состоянии
sent; - на странице несколько форм, и скрипт закрывает не ту;
- тема или конструктор перехватывает события и мешает стандартному поведению CF7.
Что проверить до правки кода
Перед тем как писать JavaScript, откройте консоль браузера и проверьте, нет ли ошибок на странице. Если в консоли уже есть Uncaught TypeError или конфликт jQuery, любые обработчики CF7 могут не выполниться. Также убедитесь, что форма действительно отправляется через AJAX: если скрипты плагина отключены, события wpcf7mailsent не сработают.
- нет ли ошибок JavaScript в консоли;
- подключается ли
wp-content/plugins/contact-form-7/includes/js/index.jsили аналогичный скрипт CF7; - не отключает ли оптимизатор JS для Contact Form 7;
- не дублируется ли jQuery в теме;
- не обёрнута ли форма в нестандартный iframe или тяжёлый popup-скрипт.
Как закрыть форму и сбросить поля после успешной отправки
У Contact Form 7 есть готовые события, которые удобно использовать без хаков ядра. Для успешной отправки подходит событие wpcf7mailsent. Если нужно просто очистить форму, можно вызвать reset у элемента формы. Если форма находится в модальном окне, в этом же обработчике можно закрыть контейнер.
Ниже пример для обычной формы, которая должна очищаться после успеха:
document.addEventListener('wpcf7mailsent', function(event) {
var form = event.target;
if (form && typeof form.reset === 'function') {
form.reset();
}
});Этот вариант работает, если форма не пересоздаётся скриптом темы и не находится внутри сложного виджета, который сам управляет состоянием полей. В большинстве случаев этого достаточно, чтобы после успешной отправки пользователь увидел пустую форму для следующего обращения.
Если форму нужно закрыть в модальном окне
Когда форма открыта в popup, логика обычно такая: после wpcf7mailsent закрыть окно и при необходимости очистить поля. Здесь важно не привязываться к абстрактному «модальному окну», а вызвать метод конкретного плагина или темы. Универсального API у всех popup-решений нет, поэтому ниже — безопасный шаблон, который вы адаптируете под свой стек.
document.addEventListener('wpcf7mailsent', function(event) {
var form = event.target;
var popup = form.closest('.my-popup, .modal, .popup');
if (form && typeof form.reset === 'function') {
form.reset();
}
if (popup) {
popup.classList.remove('is-open');
popup.setAttribute('aria-hidden', 'true');
}
});Здесь селекторы .my-popup, .modal, .popup — это пример. В реальном проекте оставьте только тот класс, который использует ваша тема или плагин. Иначе вы рискуете закрыть не тот блок или вообще ничего не закрыть.
Диагностика: почему событие не срабатывает
Если код добавлен, но форма всё равно не закрывается, проблема обычно в одном из трёх мест: скрипт не загружен, обработчик навешан слишком рано или форма рендерится динамически после загрузки страницы. В этом случае полезно сначала проверить само событие.
Добавьте временный лог в консоль:
document.addEventListener('wpcf7mailsent', function(event) {
console.log('CF7 success:', event.detail.contactFormId, event.target);
});Если сообщение в консоли не появляется, значит:
- форма отправляется не через стандартный AJAX Contact Form 7;
- скрипт плагина отключён оптимизатором;
- на странице есть JS-ошибка до регистрации обработчика;
- форма подгружается после события
DOMContentLoadedи ваш код не учитывает это.
Если лог появляется, но форма не закрывается, значит проблема уже в селекторе или в API модального окна.
Пошаговое решение для темы или дочерней темы
Самый практичный вариант — добавить небольшой JS-файл в дочернюю тему и подключить его через wp_enqueue_script. Так код не потеряется после обновления и не будет размазан по шаблонам.
1. Подключите отдельный JS-файл
add_action('wp_enqueue_scripts', function () {
wp_enqueue_script(
'cf7-form-behavior',
get_stylesheet_directory_uri() . '/assets/js/cf7-form-behavior.js',
array(),
'1.0.0',
true
);
});Если у вас уже есть сборка фронтенда, добавьте код в существующий бандл. Отдельный файл удобен, когда нужно быстро отладить поведение без пересборки всего проекта.
2. Добавьте обработчик успешной отправки
document.addEventListener('wpcf7mailsent', function(event) {
var form = event.target;
if (form && typeof form.reset === 'function') {
form.reset();
}
var popup = form.closest('.modal.is-open');
if (popup) {
popup.classList.remove('is-open');
popup.setAttribute('aria-hidden', 'true');
}
});Если у вас другая логика открытия модалки, замените закрытие на вызов метода вашего popup-скрипта. Главное — не пытаться закрыть окно через «магическую» функцию без проверки, существует ли она в проекте.
3. Сбросьте дополнительные поля вручную, если они не очищаются
Иногда стандартный reset() не сбрасывает кастомные элементы: select2, datepicker, маски телефона, чекбоксы, которые управляются внешним скриптом. Тогда нужно очистить их отдельно.
document.addEventListener('wpcf7mailsent', function(event) {
var form = event.target;
form.querySelectorAll('input[type="text"], input[type="email"], input[type="tel"], textarea').forEach(function(field) {
field.value = '';
});
form.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(function(field) {
field.checked = false;
});
form.querySelectorAll('select').forEach(function(field) {
field.selectedIndex = 0;
});
});Этот вариант полезен, если форма визуально «залипает» после отправки, но использовать его нужно аккуратно: если в форме есть скрытые служебные поля, не трогайте их без необходимости.
Сравнение подходов: плагин, код или настройка темы
| Подход | Когда подходит | Минус |
|---|---|---|
| Код в дочерней теме | Нужен точный контроль над закрытием формы и сбросом полей | Требует поддержки кода |
| Настройка popup-плагина | Форма живёт внутри модального окна и плагин умеет закрываться по событию | Зависит от конкретного плагина |
| Правка шаблона темы | Форма встроена в уникальный блок темы | Сложнее обновлять и тестировать |
Если задача ограничивается только очисткой полей, достаточно JS. Если нужно закрывать popup, лучше использовать API того плагина, который этот popup и открывает. Не смешивайте несколько систем управления модалками на одной странице без необходимости.
Проверка результата после внедрения
После правки проверьте не только визуальный эффект, но и повторную отправку. Успешный сценарий выглядит так: пользователь заполняет форму, отправляет её, видит сообщение об успехе или закрытие окна, затем снова открывает форму и видит пустые поля.
- форма отправляется без перезагрузки страницы;
- в консоли нет ошибок JavaScript;
- после успеха форма очищается;
- модальное окно закрывается только у нужной формы;
- повторная отправка работает без ручного обновления страницы.
Если форма не очищается, но письмо приходит, значит проблема в фронтенде. Если форма очищается, но письмо не приходит, возвращайтесь к проверке почтовой доставки и логов сервера — это уже другая задача.
Частые ошибки и как их исправить
Обработчик повесили не на то событие
Для успешной отправки используйте wpcf7mailsent. Если повесить код на submit, форма может сбрасываться до завершения AJAX-запроса, и пользователь потеряет введённые данные.
Скрипт загружается раньше DOM
Если код выполняется до появления формы, closest() и querySelector() могут вернуть null. Решение простое: подключайте файл в футере или оборачивайте логику в обработчик события документа, как в примерах выше.
Оптимизатор отключил JS Contact Form 7
Некоторые плагины кеша и ускорения объединяют или откладывают скрипты так агрессивно, что события CF7 перестают работать. Если после включения оптимизации форма перестала закрываться, временно исключите скрипты Contact Form 7 из отложенной загрузки и проверьте результат.
Селектор модалки слишком общий
Выражение вроде .modal может закрыть не тот блок, если на странице несколько окон. Лучше привязаться к контейнеру конкретной формы или к уникальному классу popup.
Безопасность и производительность
Не вставляйте inline-скрипты прямо в шаблон, если проект уже использует отдельные JS-файлы и сборку. Это усложняет сопровождение и увеличивает риск конфликтов при обновлении темы. Для небольших правок отдельный файл в дочерней теме — более чистый вариант.
Если на сайте много форм, не навешивайте тяжёлые обработчики на каждую из них отдельно. Один глобальный listener на document обычно проще и дешевле по производительности. И не используйте сторонние библиотеки только ради закрытия popup — в большинстве случаев достаточно нативного JavaScript.
Если вам нужно не только закрытие формы, но и более сложная логика после отправки — например, показ блока благодарности, переключение шагов или запись события в аналитику — лучше вынести это в отдельный модуль. Тогда поведение формы останется предсказуемым, а отладка не превратится в поиск случайных обработчиков по всему проекту.