
🚀 Como interligar-se ao Contact Form 7 antes do envio do formulário
Contact Form 7 está instalado em milhões de sites WordPress. É simples, fiável e gratuito. Mas assim que o comportamento padrão se torna insuficiente e precisa de validar um campo, definir um destinatário dinâmico ou cancelar um email com base numa condição, entra no território do «como é que isto se faz ao certo».
A documentação do CF7 descreve os hooks de forma breve. Os fóruns e o Stack Overflow estão cheios de snippets para versões antigas do plugin, e código com cinco anos quebra silenciosamente no CF7 moderno. Vamos perceber quais são os hooks atuais e como ligar-se a eles sem surpresas.
💡 Visão geral rápida:
- o hook principal é o
wpcf7_before_send_mail, o ponto de entrada para qualquer lógica de pré-envio. - pode ignorar o envio do email usando o filtro
wpcf7_skip_mailou uma única linhaskip_mail: onnas definições do formulário. - para obter os dados submetidos, utilize o objeto
$submissione o métodoget_posted_data(). - para alterar o destinatário dinamicamente, utilize
set_properties()no objeto do formulário. - para validação de campos, utilize
wpcf7_validatecom um filtro por tipo de campo.
Por que precisa de hooks de pré-envio
O cenário padrão do CF7 é assim: um utilizador preenche os campos, clica em «Enviar», o plugin envia um email para um endereço fixo. É tudo. Adicionar lógica a este processo sem hooks é impossível.
O hook wpcf7_before_send_mail e os filtros relacionados permitem-lhe intervir na cadeia exatamente no momento em que os dados foram validados, mas o email ainda não foi enviado. Pode:
- verificar uma condição personalizada e cancelar a submissão;
- guardar os dados do formulário numa base de dados ou API externa;
- alterar o destinatário do email dinamicamente;
- modificar o conteúdo do email;
- acionar uma integração com um CRM ou serviço de mailing.
Todos os exemplos abaixo funcionam com o Contact Form 7 versão 5.2 e superior. Se o seu plugin for mais antigo, atualize primeiro: as assinaturas dos hooks antigos são incompatíveis.
Wpcf7_before_send_mail, o ponto de entrada
A partir da versão 5.2, a assinatura do hook mudou. Anteriormente, apenas o objeto do formulário era passado; agora existem três argumentos:
1 add_filter( 'wpcf7_before_send_mail', 'cf7_before_send_handler', 10, 3 ); 2 3 function cf7_before_send_handler( $contact_form, $abort, $submission ) { 4 // $contact_form — WPCF7_ContactForm object 5 // $abort — abort flag (true/false) 6 // $submission — WPCF7_Submission object with data 7 8 // your logic here 9 10 return $contact_form; 11 }
Ficheiro para colocação: functions.php do seu tema ativo ou o plugin Code Snippets. A prioridade 10 funciona para a maioria das tarefas; aumente para 1 se o seu callback precisar de ser executado antes dos outros, ou diminua para 99 se precisar de ser executado depois.
Note que este hook é um filtro, não uma ação. Deve retornar o objeto $contact_form (ou WPCF7_ContactForm), caso contrário a cadeia será interrompida incorretamente.
Ignorar o envio de email
O caso de uso mais comum: não enviar uma notificação se um campo for preenchido de uma forma específica. Existem duas abordagens.
Usar o filtro wpcf7_skip_mail
Curto e limpo. O filtro aceita um valor booleano e o objeto do formulário:
1 add_filter( 'wpcf7_skip_mail', 'maybe_skip_mail', 10, 2 ); 2 3 function maybe_skip_mail( $skip_mail, $contact_form ) { 4 $submission = WPCF7_Submission::get_instance(); 5 6 if ( $submission ) { 7 $data = $submission->get_posted_data(); 8 9 // do not send email if field your-reason equals 'test' 10 if ( 'test' === ( $data['your-reason'] ?? '' ) ) { 11 $skip_mail = true; 12 } 13 } 14 15 return $skip_mail; 16 }
O método WPCF7_Submission::get_instance() fornece acesso aos dados da submissão dentro deste filtro. Sem ele, get_posted_data() fica indisponível, uma vez que $submission não é passado diretamente para wpcf7_skip_mail.
Usar as Definições Adicionais
Se a lógica for a mais simples possível (ignorar sempre o email para um formulário específico), vá ao painel de administração. No separador «Definições Adicionais» do formulário, adicione uma linha:
1 skip_mail: on
Não requer código. O plugin interrompe o envio do email logo após a validação e o utilizador vê uma mensagem de sucesso. Perfeito para formulários de demonstração e ambientes de teste.
Uma alternativa com o mesmo efeito: demo_mode: on. A diferença é que o demo_mode simula totalmente o sucesso sem tocar no subsistema de correio, enquanto o skip_mail apenas ignora o passo de envio, preservando todos os outros comportamentos.
Obter os dados submetidos
O objeto $submission (o terceiro argumento de wpcf7_before_send_mail) dá acesso total ao que o utilizador submeteu:
1 add_filter( 'wpcf7_before_send_mail', 'cf7_read_form_data', 10, 3 ); 2 3 function cf7_read_form_data( $contact_form, $abort, $submission ) { 4 // all fields at once 5 $posted = $submission->get_posted_data(); 6 7 // specific field (key — name attribute of the tag in the form) 8 $user_name = $submission->get_posted_data( 'your-name' ); 9 $user_email = $submission->get_posted_data( 'your-email' ); 10 11 // ID of the post from which the form was sent 12 $post_id = $submission->get_meta( 'container_post_id' ); 13 14 // form ID 15 $form_id = $contact_form->id(); 16 17 // save to log or external service 18 if ( $user_email ) { 19 // for example, add subscriber to mailing list 20 } 21 22 return $contact_form; 23 }
As chaves dos campos ('your-name', 'your-email') são os valores do atributo name nos shortcodes do formulário. Tags padrão como [text* your-name], [email* your-email] produzem chaves sem prefixos; basta copiar o que vem depois do espaço.
Importante: get_posted_data() retorna os dados brutos antes do processamento pelos modelos de email. Caracteres especiais, quebras de linha, tudo como o utilizador introduziu. Higienize antes de guardar na base de dados usando sanitize_text_field() ou funções semelhantes.
Alteração dinâmica do destinatário
Suponha que o email deve ir para gestores diferentes dependendo do tópico selecionado no formulário. Alteramos a propriedade recipient dinamicamente:
1 add_filter( 'wpcf7_before_send_mail', 'cf7_dynamic_recipient', 10, 3 ); 2 3 function cf7_dynamic_recipient( $contact_form, $abort, $submission ) { 4 $data = $submission->get_posted_data(); 5 $department = $data['your-department'] ?? ''; 6 7 $recipients = [ 8 'sales' => '[email protected]', 9 'support' => '[email protected]', 10 'billing' => '[email protected]', 11 ]; 12 13 if ( isset( $recipients[ $department ] ) ) { 14 $props = $contact_form->get_properties(); 15 $props['mail']['recipient'] = $recipients[ $department ]; 16 $contact_form->set_properties( $props ); 17 } 18 19 return $contact_form; 20 }
Os métodos get_properties() e set_properties() trabalham com o array de definições do formulário, incluindo a secção mail. Pode alterar não só o destinatário, mas também o assunto (subject), corpo (body), cabeçalhos adicionais (additional_headers) e remetente (sender).
Coloque o código no mesmo local: o functions.php do seu tema ou via Code Snippets. Teste em staging antes de implementar em produção: um erro de digitação na chave do array mail será ignorado silenciosamente e o email será enviado para o endereço padrão.
Validação de campos antes do envio
O CF7 fornece o filtro wpcf7_validate, que é acionado antes do wpcf7_before_send_mail. Ele recebe um objeto WPCF7_Validation e permite adicionar um erro; o formulário não será submetido até que o utilizador o corrija:
1 add_filter( 'wpcf7_validate_text*', 'cf7_custom_text_validation', 10, 2 ); 2 add_filter( 'wpcf7_validate_email*', 'cf7_custom_email_validation', 10, 2 ); 3 4 function cf7_custom_text_validation( $result, $tag ) { 5 $field_name = $tag->name; 6 7 if ( 'your-message' === $field_name ) { 8 $value = $_POST[ $field_name ] ?? ''; 9 10 if ( mb_strlen( $value ) < 20 ) { 11 $result->invalidate( $tag, 'Message must be at least 20 characters long.' ); 12 } 13 } 14 15 return $result; 16 } 17 18 function cf7_custom_email_validation( $result, $tag ) { 19 $value = $_POST[ $tag->name ] ?? ''; 20 21 if ( $value && ! str_contains( $value, '@' ) ) { 22 $result->invalidate( $tag, 'Enter a valid email.' ); 23 } 24 25 return $result; 26 }
O filtro é nomeado seguindo o padrão wpcf7_validate_<field type>: text* para campos de texto obrigatórios, email* para email, textarea* para áreas de texto. Sem o asterisco, aplica-se a campos opcionais. $tag é um objeto com os parâmetros do campo do formulário, incluindo name.
Os erros são adicionados usando o método invalidate($tag, 'error text'). O texto é arbitrário e é exibido abaixo do campo do formulário. Para submissão AJAX (o padrão no CF7), a mensagem aparece sem recarregar a página.
⁉️🤔 Perguntas frequentes
Qual é a diferença entre wpcf7_before_send_mail e wpcf7_mail_sent?
O
wpcf7_before_send_mailé acionado antes do envio do email; pode cancelar o email, alterar o destinatário ou modificar os dados nele. Owpcf7_mail_senté uma ação que é acionada depois do envio bem-sucedido. Utilize-o para registo de logs, acionar webhooks ou escritas na base de dados quando o envio do email é garantido. Se precisar de interromper o processo, apenas obefore_send_mailfuncionará.
Posso ligar-me a um hook sem editar o functions.php?
Sim, através do plugin Code Snippets (gratuito, no repositório do WordPress). Ele fornece uma interface para adicionar snippets PHP sem tocar no tema. Os snippets podem ser ativados e desativados individualmente, o que é conveniente para depuração. Uma alternativa é o WPCode (anteriormente Insert Headers and Footers), também gratuito e com controlo de âmbito; pode vincular um snippet a um formulário específico através de lógica condicional.
Como verifico se o hook está realmente a ser acionado?
A forma mais simples:
error_log( 'HOOK FIRED' )dentro da função de callback e verificarwp-content/debug.logcomWP_DEBUGativado. Para uma depuração rápida sem logs, substitua temporariamentereturn $contact_formporwp_die('Hook works'). Não faça isto num site de produção; apenas em ambientes locais ou de staging.
O que devo fazer se o meu código deixar de funcionar após uma atualização do CF7?
Primeiro, verifique a assinatura do hook. Na versão 5.2, o número de argumentos para
wpcf7_before_send_mailaumentou de 1 para 3. Se o seu callback estiver declarado sem o parâmetro$submission, adicione-o. Segundo, verifique se a sua função retorna o objeto$contact_form. Terceiro, verifique o registo de erros do PHP; o CF7 ignora silenciosamente erros fatais dentro dos hooks, o formulário é submetido como habitualmente e não vê o problema.
Existe uma forma de subscrever vários formulários com um único hook?
Sim, o
wpcf7_before_send_mailé acionado para todos os formulários. Dentro do callback, filtre por ID:$contact_form->id()retorna um número correspondente ao ID do shortcode do formulário (por exemplo,[contact-form-7 id="42"]). Compare-o com os IDs necessários e execute lógicas diferentes através deifouswitch.
O que colocar no functions do tema vs. extrair para um plugin
Os hooks do CF7 funcionam tecnicamente a partir de qualquer lugar: functions.php, Code Snippets, MU-plugin. Mas existe uma divisão prática que evitará dores de cabeça ao mudar de temas ou ao atualizar.
O código ligado à lógica de negócio (alteração de destinatário, integração com CRM, gravações na base de dados) deve ir para um plugin separado ou para o Code Snippets. A razão é simples: mudar de tema não deve quebrar o encaminhamento de emails do cliente. A validação de campos, que está frequentemente ligada ao layout e às classes do tema, pode permanecer no functions.php; perderá o sentido quando o tema mudar, de qualquer forma.
Snippets com mais de 30 linhas devem ser formatados como um MU-plugin (wp-content/mu-plugins/cf7-custom.php). Os MU-plugins não podem ser desativados a partir do painel de administração, são executados antes dos plugins regulares e não requerem ativação; basta colocar o ficheiro na pasta e o código funciona.
Para casos completamente isolados (um formulário, um site), utilize o functions.php juntamente com um tema filho. Menos ficheiros, menos confusão.
Estes mesmos princípios aplicam-se a qualquer outro plugin de formulários, seja ele o WPForms, o Gravity Forms ou o Fluent Forms. Cada um tem os seus próprios hooks, mas a abordagem arquitetural de «lógica de negócio separada, lógica de apresentação com o tema» é universal.
O vídeo fornece uma análise passo a passo da validação de campos personalizada do CF7 com um exemplo ao vivo no painel de administração do WordPress. A abordagem é compatível com o filtro wpcf7_validate descrito acima, por isso veja-o como um complemento visual ao código da secção de validação.



