
🐛 Contact Form 7 num popup do Elementor: porque o formulário recarrega a página e como resolver
Adiciona um formulário de contacto através do Contact Form 7 dentro de um popup do Elementor Pro. O utilizador preenche os campos, clica em «Enviar» e a página inteira é recarregada.
Sem mensagens de erro. Sem confirmação de envio. Apenas um recarregamento e um lead perdido.
Este é um conflito conhecido: o CF7 depende de submissão por AJAX, mas dentro de um popup carregado dinamicamente o seu JavaScript não tem tempo para se ligar ao formulário. Como resultado, o navegador executa um envio HTML padrão, precisamente aquele que causa o recarregamento.
O problema existe há anos, mas resolve-se com apenas duas linhas de código. Abaixo encontram-se duas soluções funcionais: uma moderna (mais limpa e fiável) e uma alternativa do GitHub, além de melhorias opcionais e uma lista de verificação para depuração.
💡 Resumo rápido:
- Causa raiz: o CF7 inicializa no carregamento da página, mas o popup com o formulário aparece mais tarde, pelo que o script desconhece o seu conteúdo
- Solução 1: reinicializar o CF7 quando o evento
elementor/popup/showé disparado; o JavaScript aguarda que o popup abra e assume o formulário - Solução 2: monitorizar cliques no botão que abre o popup com um atraso para a animação; este método provém de uma discussão no GitHub sobre o Elementor
- Opcional: repor o formulário ao reabrir e fechar automaticamente o popup após um envio bem-sucedido
- Lista de verificação para depuração: consola do navegador, conflitos de jQuery, plugins de cache
Porque é que o CF7 falha especificamente num popup

O Contact Form 7 é construído sobre AJAX: o formulário é enviado sem recarregar, a validação dos campos acontece em tempo real e as mensagens de erro ou sucesso aparecem instantaneamente. No entanto, todo este mecanismo se liga ao DOM no carregamento da página através de uma chamada a wpcf7.init().
O Elementor Pro carrega o conteúdo do popup dinamicamente, após o evento DOMContentLoaded. Quando um utilizador clica num botão e o popup abre, o seu HTML é inserido no documento, mas o CF7 desconhece-o por completo. O formulário dentro do popup permanece não inicializado.
O que acontece a seguir: sem um manipulador AJAX ativo, o navegador executa um envio de formulário HTML padrão. O atributo action é disparado e a página recarrega. O popup fecha naturalmente (o seu estado é reposto na navegação). O utilizador vê um recarregamento e abandona a página.
Muitos programadores tentam tratar os sintomas: bloqueiam o fecho do popup com event.stopPropagation(), sobrepõem funções internas do Elementor ou impedem o envio do formulário com e.preventDefault(). Nenhum destes métodos aborda a causa raiz (a falta de inicialização do CF7). Alguns até quebram as animações do popup ou o próprio Elementor em todo o site.
Existe apenas uma solução fiável: esperar que o popup abra e chamar explicitamente wpcf7.init() para cada formulário no seu interior.
Solução 1: reinicialização ao abrir o popup (abordagem moderna)
Este método utiliza o evento nativo elementor/popup/show do Elementor. Coloque o código no functions.php do seu tema ativo ou adicione-o através de um plugin de snippets como o Code Snippets.
Crie uma cópia de segurança do functions.php antes de editar.
1 /** 2 * Reinitialize Contact Form 7 when opening an Elementor popup. 3 * Fixes page reload after form submission. 4 */ 5 function 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 } 18 add_action( 'wp_footer', 'sdstudio_cf7_reinit_in_popup' );
Depois de guardar, abra o popup com o formulário e teste-o: preencha os campos obrigatórios incorretamente e clique em «Enviar». As mensagens de validação devem aparecer instantaneamente, sem recarregamento. Em seguida, envie o formulário corretamente e confirme que a mensagem de sucesso também é exibida dentro do popup.
O código aguarda o evento elementor/popup/show, que é garantido disparar após o conteúdo do popup ter sido renderizado. Depois, querySelectorAll encontra todos os formulários CF7 no DOM atual e wpcf7.init() liga forçosamente a validação e submissão AJAX a cada um deles. A verificação typeof wpcf7 !== 'undefined' protege contra erros se, por alguma razão, o CF7 não tiver carregado.
Solução 2: monitorizar cliques no botão do popup (método alternativo)
Esta abordagem foi publicada na discussão #7798 do GitHub do Elementor pelo utilizador @drinkmaker. Em vez de monitorizar a abertura do popup, monitoriza cliques num botão ou link com href='#elementor-action', que é exatamente como o Elementor aciona os popups.
O atraso setTimeout(..., 800) concede tempo para a animação de aparecimento do popup antes de o código encontrar e inicializar o formulário. O marcador .elementor impede a reinicialização do mesmo formulário duas vezes.
1 /** 2 * Alternative initialization of CF7 in Elementor popups. 3 * Source: https://github.com/elementor/elementor/issues/7798 (drinkmaker) 4 */ 5 function 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 } 27 add_action( 'wp_footer', 'sdstudio_elementor_cf7_alt_init' );
Qual o método a escolher: o primeiro (usando o evento elementor/popup/show) é preferível porque depende da API documentada do Elementor, é mais limpo e não depende de temporizadores. O segundo foi testado em produção durante anos e serve como um Plano B fiável se o primeiro não funcionar por algum motivo.
Opcional: repor o formulário ao reabrir
Quando um utilizador fecha o popup e o abre novamente, os campos do formulário permanecem preenchidos. Isto é confuso: não fica claro se o formulário foi ou não enviado. Uma pequena adição à primeira solução resolve isto:
1 /** 2 * Reset CF7 form each time an Elementor popup opens. 3 */ 4 function 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 } 18 add_action( 'wp_footer', 'sdstudio_cf7_reset_on_popup_open' );
A função repõe os valores dos campos com reset(), remove as classes CSS dos campos inválidos, oculta as mensagens de envio e remove as dicas de validação. O utilizador vê sempre um formulário limpo.
Opcional: fechar o popup após envio bem-sucedido
Após um envio bem-sucedido, faz sentido fechar automaticamente o popup após 1,5 segundos, para que o utilizador tenha tempo de ler a confirmação sem ter de procurar o botão de fechar:
1 /** 2 * Auto-close Elementor popup after successful CF7 submission. 3 */ 4 function 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 } 15 add_action( 'wp_footer', 'sdstudio_close_popup_on_cf7_success' );
O evento wpcf7mailsent é disparado quando o servidor confirma que o email foi enviado. O atraso de 1500 ms dá ao utilizador tempo para ler a mensagem de sucesso. O clique em .dialog-close-button utiliza o botão de fechar padrão do Elementor. Ao contrário das tentativas de chamar a API do popup diretamente, este método é estável em todas as versões.
Lista de verificação para depuração
Se o formulário continuar a recarregar a página após adicionar o código, siga estes passos:
Consola do navegador. Abra as DevTools (F12 → Consola) e verifique se há erros de JavaScript a vermelho. Uma causa comum é o jQuery não estar a carregar ou estar em conflito com outro plugin.
Cache. Plugins como WP Rocket, Autoptimize ou cache ao nível do servidor podem minificar e combinar scripts. Desative temporariamente a otimização agressiva de JS e teste novamente.
jQuery em modo noConflict. Se um tema ou plugin envolver o jQuery em
noConflict, substituajQuerypor$usando um invólucro apropriado ou utilize a forma completajQuery.ID do popup. Certifique-se de que o formulário está dentro do popup exato acionado por um botão com
href='#elementor-action'. Para popups abertos através de outros tipos de acionamento (por exemplo, temporizador), o primeiro método comelementor/popup/showé mais fiável.Conflito de plugins. Desative outros plugins um a um e teste, especialmente aqueles que adicionam os seus próprios scripts de validação ou modificam o comportamento dos formulários.
Versão do CF7. Estas soluções foram testadas no Contact Form 7 versão 5.7+ e Elementor Pro 3.5+. Se a sua versão do CF7 for inferior à 5.7, a função
wpcf7.init()pode ter um nome diferente; atualize o plugin.
⁉️🤔 Perguntas frequentes
Porque é que o CF7 funciona numa página normal mas falha num popup?
Quando uma página normal carrega, o DOM já está construído e o CF7 tem tempo para inicializar todos os formulários. O popup do Elementor carrega conteúdo de forma assíncrona, depois de o CF7 ter terminado o seu trabalho. O formulário acaba no DOM, mas sem um manipulador JavaScript vinculado. É por isso que verificar «funciona numa página separada» não ajuda: as condições de carregamento são fundamentalmente diferentes. A solução é sempre a reinicialização forçada quando o popup abre, independentemente de o formulário funcionar noutro local.
Posso resolver sem código, usando um plugin ou uma configuração?
Não existe um plugin pronto que permita «marcar uma caixa e já está» para este bug. O problema situa-se na interseção de dois produtos independentes (Elementor e CF7), e cada um funciona corretamente por si só. Extensões de terceiros como o WPB Popup for Contact Form 7 resolvem o problema de forma diferente: criam os seus próprios popups em vez de corrigir o Elementor. O código acima é a intervenção mínima necessária. Adiciona-o uma vez ao
functions.phpe não requer atualizações quando saem novas versões do CF7 ou do Elementor.
O primeiro método não funcionou. O que devo verificar antes de mudar para o segundo?
Verifique três coisas. Primeiro: o evento
elementor/popup/showestá disponível a partir do Elementor Pro 2.7; se a sua versão for inferior, use o segundo método de imediato. Segundo: abra a consola e escrevatypeof wpcf7; se forundefined, o plugin CF7 não carregou o seu JavaScript (procure erros ou conflitos). Terceiro: certifique-se de que o formulário dentro do popup tem a classe.wpcf7; sem ela, o seletorquerySelectorAll('.wpcf7 form')não encontrará nada. Na grande maioria dos casos, o primeiro método funciona imediatamente. Se não funcionar, use o segundo: foi comprovado em centenas de sites ao longo dos anos.
Preciso de adicionar os três snippets ou basta um?
O primeiro snippet (reinicialização) é o mínimo essencial. O segundo é uma alternativa; adicione-o apenas se o primeiro não resolveu o problema. A reposição do formulário e o fecho automático do popup são melhorias opcionais que pode adicionar conforme necessário: a reposição é útil se o popup abrir várias vezes durante uma única visita; o fecho automático é útil se o popup for usado para pedidos de contacto e não contiver um texto de confirmação extenso. Todos os três snippets são independentes e podem funcionar em simultâneo. Não há conflitos entre eles.
Após a correção, o formulário envia, mas os emails não chegam. Isto está relacionado?
Não, os problemas de entrega de email são um tópico separado, não relacionado com o funcionamento do CF7 dentro de um popup. Se, após aplicar a correção, o formulário mostrar uma mensagem de sucesso (borda verde), a submissão AJAX está a funcionar corretamente. Emails que não chegam: verifique as configurações SMTP, os filtros de spam do alojamento e o endereço do destinatário nas configurações do formulário CF7. Para uma entrega fiável, use um plugin SMTP como o Post SMTP ou FluentSMTP em vez da função padrão
wp_mail(), uma vez que os alojamentos bloqueiam frequentemente o envio de correio PHP.
Esta solução afeta outros formulários CF7 no site?
Não. Ambos os métodos são isolados: o primeiro aguarda que um popup do Elementor abra, o segundo monitoriza apenas links com
href='#elementor-action'. Os formulários CF7 normais colocados em páginas e widgets continuam a funcionar normalmente; são inicializados no carregamento da página e permanecem inalterados. A única ressalva: se o seu site usar cache agressiva com concatenação de scripts, adicione o código do popup às exclusões de minificação para evitar a execução dupla.
Vale a pena preocupar-se com código personalizado em 2026
Ambos os plugins, Contact Form 7 e Elementor Pro, são ativamente desenvolvidos e atualizados. O CF7 mantém a sua posição como o plugin de formulários WordPress mais popular, com mais de 5 milhões de instalações ativas. O Elementor Pro é usado em cada quarto site WordPress.
No entanto, o bug aqui descrito não foi corrigido ao nível do núcleo de nenhum dos plugins e provavelmente nunca será. A razão é arquitetural: o CF7 é responsável pelos formulários, o Elementor é responsável pelo conteúdo dinâmico, e a inicialização de scripts em DOM carregado dinamicamente continua a ser da responsabilidade do programador.
A boa notícia: a correção é trivial, o código é adicionado uma vez e não requer manutenção. Escolha o primeiro método (o evento elementor/popup/show): é o mais limpo e pode esquecer o problema. Se o formulário no popup for usado para cenários críticos de geração de leads, adicione também a reposição de campos e o fecho automático: a experiência do utilizador melhorará notoriamente.
Veja o vídeo acima: mostra o processo completo de configuração de um popup com o Contact Form 7 no Elementor. Este guia visual passo a passo complementa os snippets aqui fornecidos e ajuda a evitar erros durante a montagem.



