Skip to content

Wszystko o WordPressie, tworzeniu stron — i nie tylko

🐛 Contact Form 7 w popupie Elementor: dlaczego formularz przeładowuje stronę i jak to naprawić

🐛 Contact Form 7 w popupie Elementor: dlaczego formularz przeładowuje stronę i jak to naprawić

Dodają Państwo formularz kontaktowy przez Contact Form 7 w popupie Elementor Pro. Użytkownik wypełnia pola, klika „Wyślij" i strona przeładowuje się całkowicie.

Żadnych komunikatów o błędzie. Żadnego potwierdzenia wysłania. Po prostu przeładowanie i utracony lead.

To znany konflikt: CF7 jest zaprojektowany do wysyłania AJAX, ale wewnątrz dynamicznie załadowanego popupa jego JavaScript nie zdąża podpiąć się do formularza. W rezultacie przeglądarka wykonuje zwykły HTML-submit, ten sam, który powoduje przeładowanie.

Problem ma już kilka lat, ale naprawia się go dwoma linijkami kodu. Poniżej dwa działające rozwiązania: nowoczesne (czystsze i pewniejsze) oraz alternatywne z GitHuba, plus opcjonalne ulepszenia i checklista debugowania.

💡 Szybki przegląd:

  • Źródło problemu: CF7 inicjalizuje się podczas ładowania strony, a popup z formularzem pojawia się później, skrypt nie wie o jego zawartości
  • Rozwiązanie 1: reinicjalizacja CF7 przy zdarzeniu elementor/popup/show, JavaScript czeka na otwarcie popupa i przechwytuje formularz
  • Rozwiązanie 2: śledzenie kliknięcia przycisku otwierającego popup z opóźnieniem na animację, metoda z dyskusji na GitHubie Elementora
  • Opcjonalnie: resetowanie formularza przy ponownym otwarciu i automatyczne zamykanie popupa po udanym wysłaniu
  • Checklista debugowania: konsola przeglądarki, konflikty jQuery, wtyczki cache'ujące

Dlaczego CF7 psuje się właśnie w popupie

Programista naprawia błąd Contact Form 7 w WordPressie

Contact Form 7 jest zbudowany na AJAX-ie: formularz wysyła się bez przeładowania, walidacja pól odbywa się na bieżąco, komunikaty o błędach lub sukcesie pojawiają się natychmiast. Ale cały ten mechanizm jest podpinany do DOM podczas ładowania strony, przez wywołanie wpcf7.init().

Elementor Pro ładuje zawartość popupa dynamicznie, już po zdarzeniu DOMContentLoaded. Kiedy użytkownik klika przycisk i popup się otwiera, jego HTML jest wstawiany do dokumentu, ale CF7 o tym nie wie. Formularz wewnątrz popupa pozostał niezainicjalizowany.

Co dzieje się dalej: bez aktywnego handlera AJAX przeglądarka wykonuje zwykłe HTML-owe wysłanie formularza. Uruchamia się atrybut action i strona się przeładowuje. Popup zamyka się naturalnie (jego stan jest resetowany podczas nawigacji). Użytkownik widzi przeładowanie i odchodzi.

Wielu developerów próbuje leczyć objawy: blokują zamknięcie popupa przez event.stopPropagation(), nadpisują wewnętrzne funkcje Elementora, zapobiegają wysłaniu formularza przez e.preventDefault(). Żadna z tych metod nie rozwiązuje pierwotnej przyczyny, czyli braku inicjalizacji CF7. A część psuje animacje popupów lub samego Elementora na całej stronie.

Niezawodne rozwiązanie jest jedno: poczekać na otwarcie popupa i jawnie wywołać wpcf7.init() dla każdego formularza w środku.

Rozwiązanie 1: reinicjalizacja przy otwarciu popupa (nowoczesne podejście)

Ta metoda wykorzystuje natywne zdarzenie Elementora elementor/popup/show. Kod umieszcza się w functions.php aktywnego motywu lub przez wtyczkę do snippetów, taką jak Code Snippets.

Proszę zrobić kopię zapasową pliku functions.php przed edycją.

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' );

Po zapisaniu proszę otworzyć popup z formularzem i sprawdzić: wypełnić pola obowiązkowe niepoprawnie, kliknąć „Wyślij". Komunikaty walidacji powinny pojawić się natychmiast, bez przeładowania. Następnie wysłać formularz poprawnie i upewnić się, że komunikat o sukcesie również wyświetla się wewnątrz popupa.

Kod czeka na zdarzenie elementor/popup/show, które gwarantowanie uruchamia się po wyrenderowaniu zawartości popupa. Następnie querySelectorAll znajduje wszystkie formularze CF7 w bieżącym DOM, a wpcf7.init() wymusza podpięcie do każdego z nich walidacji AJAX i wysyłania. Sprawdzenie typeof wpcf7 !== 'undefined' zabezpiecza przed błędami, gdyby CF7 z jakiegoś powodu się nie załadował.

Rozwiązanie 2: śledzenie kliknięcia przycisku popupa (metoda alternatywna)

Ten sposób został umieszczony w dyskusji na GitHubie Elementor #7798 przez użytkownika @drinkmaker. Śledzi on nie otwarcie popupa, a kliknięcie przycisku lub linku z atrybutem href='#elementor-action', właśnie takich linków Elementor używa do wywoływania popupów.

Opóźnienie setTimeout(..., 800) daje czas na animację pojawienia się popupa, zanim kod znajdzie i zainicjalizuje formularz. Znacznik .elementor zapobiega ponownej inicjalizacji tego samego formularza.

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' );

Którą metodę wybrać: pierwsza (na zdarzeniu elementor/popup/show) jest lepsza, opiera się na udokumentowanym API Elementora, jest czystsza i nie zależy od timeoutów. Druga jest sprawdzona latami w produkcji i służy jako niezawodny plan B, gdyby pierwsza z jakiegoś powodu nie zadziałała.

Dodatkowo: resetowanie formularza przy ponownym otwarciu

Kiedy użytkownik zamyka popup i otwiera go ponownie, pola formularza pozostają wypełnione. To dezorientuje: nie wiadomo, czy formularz został wysłany, czy nie. Naprawia się to niewielkim uzupełnieniem pierwszego rozwiązania:

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' );

Funkcja resetuje wartości pól metodą reset(), usuwa klasy CSS nieprawidłowych pól, ukrywa komunikaty o wysłaniu i usuwa podpowiedzi walidacji. Użytkownik zawsze widzi czysty formularz.

Dodatkowo: zamykanie popupa po udanym wysłaniu

Po udanym submicie rozsądnie jest automatycznie zamknąć popup po 1,5 sekundy, użytkownik zdąża przeczytać potwierdzenie i nie musi ręcznie szukać krzyżyka:

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' );

Zdarzenie wpcf7mailsent uruchamia się, gdy serwer potwierdził wysłanie maila. Opóźnienie 1500 ms daje użytkownikowi czas na przeczytanie komunikatu o sukcesie. Kliknięcie .dialog-close-button używa standardowego przycisku zamykania Elementora, w przeciwieństwie do prób bezpośredniego wywoływania API popupa, ta metoda jest stabilna na wszystkich wersjach.

Checklista debugowania

Jeśli po dodaniu kodu formularz nadal przeładowuje stronę, proszę przejść przez punkty:

  • Konsola przeglądarki. Proszę otworzyć DevTools (F12 → Console) i sprawdzić obecność czerwonych błędów JavaScript. Częsta przyczyna: jQuery nie jest załadowane lub konfliktuje z inną wtyczką.

  • Cache'owanie. Wtyczki takie jak WP Rocket, Autoptimize lub cache hostingowy mogą minifikować i łączyć skrypty. Proszę tymczasowo wyłączyć agresywną optymalizację JS i sprawdzić ponownie.

  • jQuery w trybie noConflict. Jeśli motyw lub wtyczka opakowują jQuery w noConflict, proszę zastąpić jQuery przez $ z odpowiednią obwolutą lub używać pełnej formy jQuery.

  • ID popupa. Proszę upewnić się, że formularz znajduje się dokładnie w tym popupie, który jest wywoływany przyciskiem z href='#elementor-action'. Dla popupów otwieranych przez triggery innego typu (np. timerem) pierwsza metoda z elementor/popup/show jest pewniejsza.

  • Konflikt wtyczek. Proszę dezaktywować pozostałe wtyczki pojedynczo i sprawdzać, szczególnie te, które dodają własne skrypty walidacji lub modyfikują zachowanie formularzy.

  • Wersja CF7. Rozwiązania są sprawdzone na Contact Form 7 w wersji 5.7+ oraz Elementor Pro 3.5+. Jeśli wersja CF7 jest niższa niż 5.7, funkcja wpcf7.init() może nazywać się inaczej, proszę zaktualizować wtyczkę.

⁉️🤔 Często zadawane pytania

Dlaczego CF7 działa na zwykłej stronie, ale psuje się w popupie?

Podczas ładowania zwykłej strony DOM jest już zbudowany i CF7 zdąża zainicjalizować wszystkie formularze. Popup Elementora ładuje zawartość asynchronicznie, już po tym, jak CF7 zakończył swoją pracę. Formularz znajduje się w DOM, ale bez podpiętego handlera JavaScript. Właśnie dlatego sprawdzenie „na osobnej stronie wszystko działa" nie pomaga: warunki ładowania są zasadniczo różne. Rozwiązaniem jest zawsze wymuszona reinicjalizacja przy otwarciu popupa, niezależnie od tego, czy formularz działa gdzieś indziej.

Czy można obejść się bez kodu, za pomocą wtyczki lub ustawienia?

Gotowej wtyczki typu „zaznacz checkbox i wszystko zadziała" do tego buga nie ma. Problem leży na styku dwóch niezależnych produktów (Elementor i CF7) i każdy z nich działa poprawnie osobno. Zewnętrzne dodatki, takie jak WPB Popup for Contact Form 7, rozwiązują zadanie inaczej, tworzą własne popupy, a nie naprawiają Elementora. Powyższy kod to minimalna niezbędna ingerencja. Dodaje się go raz w functions.php i nie wymaga aktualizacji przy nowych wersjach CF7 ani Elementora.

Pierwsza metoda nie zadziałała. Co sprawdzić przed przejściem do drugiej?

Proszę sprawdzić trzy rzeczy. Po pierwsze: zdarzenie elementor/popup/show jest dostępne od Elementor Pro 2.7, jeśli wersja jest niższa, proszę od razu użyć drugiej metody. Po drugie: proszę otworzyć konsolę i wpisać typeof wpcf7, jeśli undefined, wtyczka CF7 nie załadowała swojego JavaScriptu (proszę szukać błędów lub konfliktów). Po trzecie: proszę upewnić się, że formularz wewnątrz popupa ma klasę .wpcf7, bez niej selektor querySelectorAll('.wpcf7 form') nic nie znajdzie. W przeważającej większości przypadków pierwsza metoda działa od razu. Jeśli nie, proszę użyć drugiej, jest sprawdzona latami na setkach stron.

Czy trzeba dodawać wszystkie trzy snippety, czy wystarczy jeden?

Pierwszy snippet (reinicializacja) to obowiązkowe minimum. Drugi, alternatywny, proszę dodać tylko wtedy, gdy pierwszy nie rozwiązał problemu. Resetowanie formularza i autozamykanie popupa to opcjonalne ulepszenia, proszę je podłączać w razie potrzeby: resetowanie jest przydatne, jeśli popup otwiera się wielokrotnie podczas jednej wizyty; autozamykanie, jeśli popup służy do zgłoszeń i nie zawiera długiego tekstu potwierdzenia. Wszystkie trzy snippety są niezależne i mogą działać jednocześnie. Nie ma między nimi konfliktów.

Po poprawce formularz się wysyła, ale maile nie przychodzą. Czy to jest powiązane?

Nie, problem dostarczalności maili to osobny temat, niemający związku z działaniem CF7 w popupie. Jeśli po zastosowaniu poprawki formularz pokazuje komunikat o sukcesie (zielona ramka), oznacza to, że wysyłanie AJAX działa poprawnie. Jeśli maile nie dochodzą, proszę sprawdzić ustawienia SMTP, filtry antyspamowe hostingu oraz poprawność adresu odbiorcy w ustawieniach formularza CF7. Dla niezawodnej dostarczalności proszę używać wtyczki SMTP, takiej jak Post SMTP lub FluentSMTP, a nie standardowej funkcji wp_mail(), hostingi często blokują wychodzące maile z PHP.

Czy to rozwiązanie wpływa na inne formularze CF7 na stronie?

Nie. Obie metody są izolowane: pierwsza czeka na otwarcie popupa Elementora, druga śledzi tylko linki z href='#elementor-action'. Zwykłe formularze CF7 umieszczone na stronach i w widgetach nadal działają standardowo, ich inicjalizacja odbywa się podczas ładowania strony i nie jest naruszana. Jedyny niuans: jeśli na stronie używane jest agresywne cache'owanie z łączeniem skryptów, proszę dodać kod popupów do wyjątków minifikacji, aby uniknąć podwójnego wykonania.

Czy warto zawracać sobie głowę własnym kodem w 2026 roku

Obie wtyczki, Contact Form 7 i Elementor Pro, aktywnie się rozwijają i są aktualizowane. CF7 utrzymuje pozycję najpopularniejszej wtyczki formularzy WordPress z ponad 5 milionami aktywnych instalacji. Elementor Pro jest używany na co czwartej stronie opartej na WordPressie.

Przy tym opisany bug nie został naprawiony na poziomie rdzenia żadnej z wtyczek i najprawdopodobniej nie zostanie. Przyczyna jest architektoniczna: CF7 odpowiada za formularze, Elementor za dynamiczną treść, a inicjalizacja skryptów w dynamicznie podładowanym DOM pozostaje w obszarze odpowiedzialności developera.

Dobra wiadomość: poprawka jest trywialna, kod dodaje się raz i nie wymaga utrzymania. Proszę wybrać pierwszą metodę (zdarzenie elementor/popup/show), jest najczystsza, i zapomnieć o problemie. Jeśli formularz w popupie jest używany do krytycznych scenariuszy lead generation, proszę dodać jeszcze resetowanie pól i autozamykanie: doświadczenie użytkownika stanie się zauważalnie lepsze.

Proszę obejrzeć wideo powyżej, pokazuje ono pełny proces konfiguracji popupa z Contact Form 7 w Elementorze. Wizualny przewodnik krok po kroku uzupełnia podane tutaj snippety i pomaga uniknąć błędów na etapie składania.