Skip to content

Tutto per WordPress, lo sviluppo web — e non solo

🚀 Come agganciarsi a Contact Form 7 prima dell'invio del modulo

🚀 Come agganciarsi a Contact Form 7 prima dell'invio del modulo

Contact Form 7 è installato su milioni di siti WordPress. È semplice, affidabile e gratuito. Ma non appena il comportamento standard non basta più e devi validare un campo, impostare un destinatario dinamico o bloccare l'invio di un'email in base a una condizione, entri nel territorio del «come diavolo si fa».

La documentazione di CF7 descrive gli hook in modo sintetico. I forum e Stack Overflow sono pieni di snippet per vecchie versioni del plugin, e codice di cinque anni fa si rompe silenziosamente sulle versioni moderne di CF7. Vediamo quali hook sono attuali oggi e come agganciarcisi senza sorprese.

💡 Panoramica rapida:

  • l'hook principale è wpcf7_before_send_mail, il punto di ingresso per qualsiasi logica pre-invio.
  • puoi saltare l'invio dell'email usando il filtro wpcf7_skip_mail o una singola riga skip_mail: on nelle impostazioni del form.
  • per ottenere i dati inviati, usa l'oggetto $submission e il metodo get_posted_data().
  • per cambiare il destinatario dinamicamente, usa set_properties() sull'oggetto form.
  • per la validazione dei campi, usa wpcf7_validate con un filtro per tipo di campo.

Perché ti servono gli hook pre-invio

Lo scenario standard di CF7 è questo: un utente compila i campi, clicca «Invia», il plugin manda un'email a un indirizzo fisso. Tutto qui. Aggiungere logica a questo processo senza hook è impossibile.

L'hook wpcf7_before_send_mail e i filtri correlati ti permettono di intervenire nella catena esattamente nel momento in cui i dati sono stati validati ma l'email non è ancora stata inviata. Puoi:

  • verificare una condizione personalizzata e annullare l'invio;
  • salvare i dati del form su database o API esterna;
  • cambiare il destinatario dell'email al volo;
  • modificare il contenuto dell'email;
  • attivare un'integrazione con un CRM o un servizio di mailing.

Tutti gli esempi che seguono funzionano con Contact Form 7 versione 5.2 e successive. Se il tuo plugin è più vecchio, aggiornalo prima: le vecchie firme degli hook sono incompatibili.

Wpcf7_before_send_mail, il punto di ingresso

A partire dalla versione 5.2, la firma dell'hook è cambiata. Prima veniva passato solo l'oggetto form; ora ci sono tre argomenti:

1add_filter( 'wpcf7_before_send_mail', 'cf7_before_send_handler', 10, 3 );
2
3function 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}

File in cui inserirlo: functions.php del tuo tema attivo o il plugin Code Snippets. La priorità 10 va bene per la maggior parte dei casi; alzala a 1 se la tua callback deve essere eseguita prima di altre, oppure abbassala a 99 se deve essere eseguita dopo.

Nota che questo hook è un filtro, non un'azione. Devi restituire l'oggetto $contact_form (o WPCF7_ContactForm), altrimenti la catena si interromperà in modo scorretto.

Saltare l'invio dell'email

Il caso d'uso più comune: non inviare la notifica se un campo è compilato in un certo modo. Ci sono due approcci.

Usare il filtro wpcf7_skip_mail

Breve e pulito. Il filtro accetta un valore booleano e l'oggetto form:

1add_filter( 'wpcf7_skip_mail', 'maybe_skip_mail', 10, 2 );
2
3function 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}

Il metodo WPCF7_Submission::get_instance() fornisce accesso ai dati dell'invio all'interno di questo filtro. Senza, get_posted_data() non è disponibile poiché $submission non viene passato direttamente a wpcf7_skip_mail.

Usare le Impostazioni aggiuntive

Se la logica è la più semplice possibile (saltare sempre l'email per un form specifico), vai nel pannello di amministrazione. Nella scheda «Impostazioni aggiuntive» del form, aggiungi una riga:

1skip_mail: on

Nessun codice richiesto. Il plugin interrompe l'invio dell'email subito dopo la validazione e l'utente vede un messaggio di successo. Perfetto per form dimostrativi e ambienti di test.

Un'alternativa con lo stesso effetto: demo_mode: on. La differenza è che demo_mode simula completamente il successo senza toccare il sottosistema di posta, mentre skip_mail salta solo il passo di invio, preservando tutto il resto del comportamento.

Ottenere i dati inviati

L'oggetto $submission (il terzo argomento di wpcf7_before_send_mail) dà pieno accesso a ciò che l'utente ha inviato:

1add_filter( 'wpcf7_before_send_mail', 'cf7_read_form_data', 10, 3 );
2
3function 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}

Le chiavi dei campi ('your-name', 'your-email') sono i valori dell'attributo name negli shortcode del form. I tag standard come [text* your-name], [email* your-email] producono chiavi senza prefissi; copia semplicemente ciò che viene dopo lo spazio.

Importante: get_posted_data() restituisce dati grezzi, prima dell'elaborazione da parte dei template email. Caratteri speciali, interruzioni di riga, tutto come l'utente lo ha inserito. Prima di salvare su database, igienizza usando sanitize_text_field() o funzioni simili.

Cambio dinamico del destinatario

Mettiamo che l'email debba andare a diversi responsabili a seconda dell'argomento selezionato nel form. Cambiamo la proprietà recipient al volo:

1add_filter( 'wpcf7_before_send_mail', 'cf7_dynamic_recipient', 10, 3 );
2
3function 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}

I metodi get_properties() e set_properties() lavorano con l'array delle impostazioni del form, inclusa la sezione mail. Puoi cambiare non solo il destinatario ma anche l'oggetto (subject), il corpo (body), le intestazioni aggiuntive (additional_headers) e il mittente (sender).

Inserisci il codice nello stesso posto: il functions.php del tuo tema o tramite Code Snippets. Testa in staging prima di distribuire in produzione: un errore di battitura nella chiave dell'array mail verrà ignorato silenziosamente e l'email andrà all'indirizzo predefinito.

Validazione dei campi prima dell'invio

CF7 fornisce il filtro wpcf7_validate, che si attiva prima di wpcf7_before_send_mail. Riceve un oggetto WPCF7_Validation e ti permette di aggiungere un errore; il form non verrà inviato finché l'utente non lo corregge:

1add_filter( 'wpcf7_validate_text*', 'cf7_custom_text_validation', 10, 2 );
2add_filter( 'wpcf7_validate_email*', 'cf7_custom_email_validation', 10, 2 );
3
4function 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
18function 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}

Il filtro segue il pattern wpcf7_validate_<field type>: text* per i campi di testo obbligatori, email* per le email, textarea* per le aree di testo. Senza l'asterisco, si applica ai campi opzionali. $tag è un oggetto con i parametri del campo del form, incluso name.

Gli errori vengono aggiunti usando il metodo invalidate($tag, 'error text'). Il testo è arbitrario e viene mostrato sotto il campo del form. Con l'invio AJAX (predefinito in CF7), il messaggio appare senza ricaricare la pagina.

⁉️🤔 Domande frequenti

Qual è la differenza tra wpcf7_before_send_mail e wpcf7_mail_sent?

wpcf7_before_send_mail si attiva prima che l'email venga inviata; puoi annullare l'email, cambiare il destinatario o modificare i dati al suo interno. wpcf7_mail_sent è un'azione che si attiva dopo l'invio riuscito. Usala per logging, attivare webhook o scritture su database quando l'email è stata sicuramente inviata. Se devi interrompere il processo, solo before_send_mail funzionerà.

Posso agganciarmi senza modificare functions.php?

Sì, tramite il plugin Code Snippets (gratuito, nel repository WordPress). Fornisce un'interfaccia per aggiungere snippet PHP senza toccare il tema. Gli snippet possono essere attivati e disattivati singolarmente, il che è comodo per il debug. Un'alternativa è WPCode (ex Insert Headers and Footers), anch'esso gratuito e con controllo dell'ambito; puoi legare uno snippet a un form specifico tramite logica condizionale.

Come verifico che l'hook si stia effettivamente attivando?

Il modo più semplice: error_log( 'HOOK FIRED' ) dentro la funzione di callback e controllare wp-content/debug.log con WP_DEBUG abilitato. Per un debug rapido senza log, sostituisci temporaneamente return $contact_form con wp_die('Hook works'). Non farlo su un sito in produzione; solo in ambienti locali o di staging.

Cosa devo fare se il mio codice smette di funzionare dopo un aggiornamento di CF7?

Per prima cosa, controlla la firma dell'hook. Nella versione 5.2, il numero di argomenti per wpcf7_before_send_mail è passato da 1 a 3. Se la tua callback è dichiarata senza il parametro $submission, aggiungilo. Secondo, verifica che la tua funzione restituisca l'oggetto $contact_form. Terzo, controlla il log degli errori PHP; CF7 ignora silenziosamente gli errori fatali dentro gli hook, il form viene inviato come al solito e tu non vedi il problema.

C'è un modo per sottoscriversi a più form con un solo hook?

Sì, wpcf7_before_send_mail si attiva per tutti i form. Dentro la callback, filtra per ID: $contact_form->id() restituisce un numero che corrisponde all'ID dello shortcode del form (per esempio, [contact-form-7 id="42"]). Confrontalo con gli ID desiderati ed esegui logiche diverse tramite if o switch.

Cosa mettere nel functions.php del tema e cosa estrarre in un plugin

Gli hook di CF7 tecnicamente funzionano da qualsiasi parte: functions.php, Code Snippets, MU-plugin. Ma c'è una suddivisione pratica che farà risparmiare grattacapi quando si cambia tema o si aggiorna.

Il codice legato alla logica di business (cambio destinatario, integrazione CRM, salvataggi su database) dovrebbe stare in un plugin separato o in Code Snippets. Il motivo è semplice: cambiare tema non deve interrompere l'instradamento delle email del cliente. La validazione dei campi, che è spesso legata al layout e alle classi del tema, può restare in functions.php; perderà comunque significato quando il tema verrà cambiato.

Gli snippet più lunghi di 30 righe dovrebbero essere formattati come MU-plugin (wp-content/mu-plugins/cf7-custom.php). Gli MU-plugin non possono essere disattivati dal pannello di amministrazione, vengono eseguiti prima dei plugin normali e non richiedono attivazione; basta caricare il file e il codice funziona.

Per casi completamente isolati (un form, un sito), usa functions.php più un tema child. Meno file, meno confusione.

Questi stessi principi si applicano a qualsiasi altro plugin per form, che sia WPForms, Gravity Forms o Fluent Forms. Ognuno ha i propri hook, ma l'approccio architetturale «logica di business separata, logica di presentazione con il tema» è universale.

Il video fornisce una spiegazione passo passo della validazione personalizzata dei campi CF7 con un esempio dal vivo nel pannello di amministrazione di WordPress. L'approccio è compatibile con il filtro wpcf7_validate descritto sopra, quindi guardalo come supplemento visivo al codice della sezione sulla validazione.