Skip to content

Все для WordPress, веб-розробки — і не тільки

🐛 Contact Form 7 у попапі Elementor: чому форма перезавантажує сторінку і як це виправити

🐛 Contact Form 7 у попапі Elementor: чому форма перезавантажує сторінку і як це виправити

Ви додаєте форму зворотного зв’язку через Contact Form 7 у попап Elementor Pro. Користувач заповнює поля, натискає «Надіслати», і сторінка повністю перезавантажується.

Жодних повідомлень про помилку. Жодного підтвердження надсилання. Просто перезавантаження і втрачений лід.

Це відомий конфлікт: CF7 розрахований на AJAX-надсилання, але всередині динамічно завантаженого попапа його JavaScript не встигає прив’язатися до форми. У результаті браузер виконує звичайний HTML-сабміт, той самий, що й спричиняє перезавантаження.

Проблемі вже кілька років, але виправляється вона двома рядками коду. Нижче, два робочих рішення: сучасне (чистіше й надійніше) та альтернативне з GitHub, плюс опціональні покращення та чек-лист налагодження.

💡 Швидкий огляд:

  • Корінь проблеми: CF7 ініціалізується під час завантаження сторінки, а попап із формою з’являється пізніше, скрипт не знає про його вміст
  • Рішення 1: переініціалізація CF7 під час спрацювання події elementor/popup/show, JavaScript чекає на відкриття попапа й підхоплює форму
  • Рішення 2: відстеження кліку по кнопці, що відкриває попап, із затримкою на анімацію, метод з GitHub-обговорення Elementor
  • Опціонально: скидання форми під час повторного відкриття та автозакриття попапа після успішного надсилання
  • Чек-лист налагодження: консоль браузера, конфлікти jQuery, плагіни кешування

Чому CF7 ламається саме в попапі

Програміст виправляє баг Contact Form 7 у WordPress

Contact Form 7 побудований на AJAX: форма надсилається без перезавантаження, валідація полів відбувається на льоту, повідомлення про помилки або успіх з’являються миттєво. Але весь цей механізм прив’язується до DOM під час завантаження сторінки, викликом wpcf7.init().

Elementor Pro завантажує вміст попапа динамічно, вже після події DOMContentLoaded. Коли користувач клікає по кнопці й попап відкривається, його HTML вставляється в документ, але CF7 про це не знає. Форма всередині попапа залишилася непроініціалізованою.

Що відбувається далі: без активного AJAX-обробника браузер виконує звичайне HTML-надсилання форми. Спрацьовує атрибут action, і сторінка перезавантажується. Попап закривається природним чином (його стан скидається під час навігації). Користувач бачить перезавантаження й іде.

Багато розробників намагаються лікувати симптоми: блокують закриття попапа через event.stopPropagation(), перевизначають внутрішні функції Elementor, запобігають надсиланню форми через e.preventDefault(). Жоден із цих методів не вирішує кореневої причини, відсутності ініціалізації CF7. А частина ламає анімації попапів або сам Elementor на всьому сайті.

Надійне рішення одне: дочекатися відкриття попапа й явно викликати wpcf7.init() для кожної форми всередині.

Рішення 1: переініціалізація під час відкриття попапа (сучасний підхід)

Цей метод використовує нативну подію Elementor elementor/popup/show. Код розміщується у functions.php активної теми або через плагін для сніпетів на кшталт Code Snippets.

Створіть резервну копію файлу functions.php перед редагуванням.

1/**
2 * Переинициализация Contact Form 7 при открытии попапа Elementor.
3 * Решает проблему перезагрузки страницы после отправки формы.
4 */
5function sdstudio_cf7_reinit_in_popup() {
6 ?>
7 <script>
8 jQuery( document ).on( 'elementor/popup/show', function() {
9 document.querySelectorAll( '.wpcf7 form' ).forEach( function( form ) {
10 if ( typeof wpcf7 !== 'undefined' ) {
11 wpcf7.init( form );
12 }
13 });
14 });
15 </script>
16 <?php
17}
18add_action( 'wp_footer', 'sdstudio_cf7_reinit_in_popup' );

Після збереження відкрийте попап із формою та перевірте: заповніть обов’язкові поля некоректно, натисніть «Надіслати». Повідомлення валідації мають з’явитися миттєво, без перезавантаження. Потім надішліть форму правильно й переконайтеся, що повідомлення про успіх також відображається всередині попапа.

Код чекає на подію elementor/popup/show, вона гарантовано спрацьовує після рендерингу вмісту попапа. Далі querySelectorAll знаходить усі форми CF7 у поточному DOM, і wpcf7.init() примусово підключає до кожної AJAX-валідацію та надсилання. Перевірка typeof wpcf7 !== 'undefined' страхує від помилок, якщо CF7 з якоїсь причини не завантажився.

Рішення 2: відстеження кліку по кнопці попапа (альтернативний метод)

Цей спосіб розміщено в GitHub-обговоренні Elementor #7798 користувачем @drinkmaker. Він відстежує не відкриття попапа, а клік по кнопці або посиланню з атрибутом href='#elementor-action', саме такі посилання Elementor використовує для виклику попапів.

Затримка setTimeout(..., 800) дає час на анімацію появи попапа перед тим, як код знайде й проініціалізує форму. Маркер .elementor запобігає повторній ініціалізації тієї самої форми.

1/**
2 * Альтернативная инициализация CF7 в попапах Elementor.
3 * Источник: https://github.com/elementor/elementor/issues/7798 (drinkmaker)
4 */
5function sdstudio_elementor_cf7_alt_init() {
6 ?>
7 <script type='text/javascript'>
8 jQuery( document ).ready( function() {
9
10 jQuery( document ).on( 'click', "a[href='#elementor-action']", function() {
11
12 setTimeout( function() {
13
14 jQuery( '.elementor-popup-modal form.wpcf7-form:not(.elementor)' ).each( function( index ) {
15 wpcf7.initForm( jQuery( this ) );
16 jQuery( this ).addClass( 'elementor' );
17 });
18
19 }, 800 );
20
21 });
22
23 });
24 </script>
25 <?php
26}
27add_action( 'wp_footer', 'sdstudio_elementor_cf7_alt_init' );

Який метод обрати: перший (за подією elementor/popup/show) є кращим, він спирається на документоване API Elementor, чистіший і не залежить від таймаутів. Другий перевірений роками в продакшені й слугує надійним планом Б, якщо перший з якоїсь причини не спрацював.

Додатково: скидання форми під час повторного відкриття

Коли користувач закриває попап і відкриває його знову, поля форми залишаються заповненими. Це збиває з пантелику: незрозуміло, надіслана форма чи ні. Виправляється невеликим доповненням до першого рішення:

1/**
2 * Сброс формы CF7 при каждом открытии попапа Elementor.
3 */
4function sdstudio_cf7_reset_on_popup_open() {
5 ?>
6 <script>
7 jQuery( document ).on( 'elementor/popup/show', function() {
8 jQuery( '.wpcf7 form' ).each( function() {
9 this.reset();
10 jQuery( this ).find( '.wpcf7-not-valid' ).removeClass( 'wpcf7-not-valid' );
11 jQuery( this ).find( '.wpcf7-response-output' ).hide();
12 jQuery( this ).find( '.wpcf7-not-valid-tip' ).remove();
13 });
14 });
15 </script>
16 <?php
17}
18add_action( 'wp_footer', 'sdstudio_cf7_reset_on_popup_open' );

Функція скидає значення полів методом reset(), прибирає CSS-класи невалідних полів, приховує повідомлення про надсилання та видаляє підказки валідації. Користувач завжди бачить чисту форму.

Додатково: закриття попапа після успішного надсилання

Після успішного сабміту розумно автоматично закрити попап через 1,5 секунди, користувач встигає прочитати підтвердження й не шукає хрестик вручну:

1/**
2 * Автозакрытие попапа Elementor после успешной отправки CF7.
3 */
4function sdstudio_close_popup_on_cf7_success() {
5 ?>
6 <script>
7 document.addEventListener( 'wpcf7mailsent', function() {
8 setTimeout( function() {
9 jQuery( '.dialog-close-button' ).trigger( 'click' );
10 }, 1500 );
11 }, false );
12 </script>
13 <?php
14}
15add_action( 'wp_footer', 'sdstudio_close_popup_on_cf7_success' );

Подія wpcf7mailsent спрацьовує, коли сервер підтвердив надсилання листа. Затримка в 1500 мс дає користувачеві прочитати повідомлення про успіх. Клік по .dialog-close-button використовує стандартну кнопку закриття Elementor, на відміну від спроб смикати API попапа напряму, цей метод стабільний на всіх версіях.

Чек-лист налагодження

Якщо після додавання коду форма все одно перезавантажує сторінку, пройдіться за пунктами:

  • Консоль браузера. Відкрийте DevTools (F12 → Console) і перевірте наявність червоних помилок JavaScript. Часта причина, jQuery не завантажений або конфліктує з іншим плагіном.

  • Кешування. Плагіни на кшталт WP Rocket, Autoptimize або хостинговий кеш можуть мініфікувати й об’єднувати скрипти. Тимчасово вимкніть агресивну оптимізацію JS і перевірте заново.

  • jQuery у noConflict-режимі. Якщо тема або плагін обгортають jQuery у noConflict, замініть jQuery на $ із відповідною обгорткою або використовуйте повну форму jQuery.

  • ID попапа. Переконайтеся, що форма знаходиться саме в тому попапі, який викликається кнопкою з href='#elementor-action'. Для попапів, що відкриваються через тригери іншого типу (наприклад, за таймером), перший метод з elementor/popup/show надійніший.

  • Конфлікт плагінів. Деактивуйте решту плагінів по одному й перевіряйте, особливо ті, що додають власні скрипти валідації або модифікують поведінку форм.

  • Версія CF7. Рішення перевірені на Contact Form 7 версії 5.7+ та Elementor Pro 3.5+. Якщо версія CF7 нижча за 5.7, функція wpcf7.init() може називатися інакше, оновіть плагін.

⁉️🤔 Часті запитання

Чому CF7 працює на звичайній сторінці, але ламається в попапі?

Під час завантаження звичайної сторінки DOM уже побудований, і CF7 встигає проініціалізувати всі форми. Попап Elementor завантажує вміст асинхронно, після того, як CF7 завершив свою роботу. Форма опиняється в DOM, але без прив’язаного JavaScript-обробника. Саме тому перевірка «на окремій сторінці все працює» не допомагає: умови завантаження принципово різні. Рішення, завжди примусова реініціалізація під час відкриття попапа, незалежно від того, чи працює форма десь іще.

Чи можна обійтися без коду, плагіном або налаштуванням?

Готового плагіна «натисни галочку, і все запрацює» для цього бага немає. Проблема на стику двох незалежних продуктів (Elementor і CF7), і кожен із них працює коректно окремо. Сторонні надбудови на кшталт WPB Popup for Contact Form 7 вирішують задачу інакше, створюють власні попапи, а не лагодять Elementor. Наведений вище код, мінімально необхідний обсяг втручання. Він додається один раз у functions.php і не потребує оновлень під час виходу нових версій CF7 або Elementor.

Перший метод не спрацював. Що перевірити до переходу до другого?

Перевірте три речі. Перше: подія elementor/popup/show доступна починаючи з Elementor Pro 2.7, якщо версія нижча, використовуйте одразу другий метод. Друге: відкрийте консоль і введіть typeof wpcf7, якщо undefined, плагін CF7 не завантажив свій JavaScript (шукайте помилки або конфлікти). Третє: переконайтеся, що форма всередині попапа має клас .wpcf7, без нього селектор querySelectorAll('.wpcf7 form') нічого не знайде. У переважній більшості випадків перший метод працює одразу. Якщо ні, використовуйте другий, він перевірений роками на сотнях сайтів.

Чи потрібно додавати всі три сніпети, чи достатньо одного?

Перший сніпет (реініціалізація), обов’язковий мінімум. Другий, альтернатива, додайте, тільки якщо перший не вирішив проблему. Скидання форми й автозакриття попапа, опціональні покращення, підключайте за потребою: скидання корисне, якщо попап відкривається багаторазово за один візит; автозакриття, якщо попап використовується для заявок і не містить довгого тексту підтвердження. Усі три сніпети незалежні й можуть працювати одночасно. Конфліктів між ними немає.

Після виправлення форма надсилається, але листи не приходять. Це пов’язано?

Ні, проблема доставки листів, окрема тема, що не має стосунку до роботи CF7 в попапі. Якщо після застосування виправлення форма показує повідомлення про успіх (зелена рамка), значить AJAX-надсилання працює коректно. Листи не доходять, перевірте налаштування SMTP, спам-фільтри хостингу та коректність адреси отримувача в налаштуваннях форми CF7. Для надійної доставки використовуйте SMTP-плагін на кшталт Post SMTP або FluentSMTP, а не стандартну функцію wp_mail(), хостинги часто блокують вихідні листи з PHP.

Чи впливає це рішення на інші форми CF7 на сайті?

Ні. Обидва методи ізольовані: перший чекає на відкриття попапа Elementor, другий відстежує тільки посилання з href='#elementor-action'. Звичайні форми CF7, розміщені на сторінках і у віджетах, продовжують працювати штатно, їхня ініціалізація відбувається під час завантаження сторінки й не зачіпається. Єдиний нюанс: якщо на сайті використовується агресивне кешування з об’єднанням скриптів, додайте код попапів у винятки мініфікації, щоб уникнути подвійного виконання.

Чи варто морочитися із самописним кодом у 2026 році

Обидва плагіни, і Contact Form 7, і Elementor Pro, активно розвиваються й оновлюються. CF7 тримає планку найпопулярнішого форменого плагіна WordPress з понад 5 мільйонами активних установок. Elementor Pro використовують на кожному четвертому сайті під управлінням WordPress.

При цьому описаний баг не виправлено на рівні ядра жодного з плагінів, і, скоріш за все, не буде. Причина архітектурна: CF7 відповідає за форми, Elementor, за динамічний контент, а ініціалізація скриптів у динамічно підвантаженому DOM залишається зоною відповідальності розробника.

Хороша новина: виправлення тривіальне, код додається один раз і не потребує підтримки. Оберіть перший метод (подія elementor/popup/show), він найчистіший, і забудьте про проблему. Якщо форма в попапі використовується для критичних лідогенеруючих сценаріїв, додайте ще скидання полів та автозакриття: користувацький досвід стане помітно кращим.

Подивіться відео вище, у ньому показано повний процес налаштування попапа з Contact Form 7 в Elementor. Візуальне покрокове керівництво доповнює наведені тут сніпети й допомагає уникнути помилок на етапі збирання.