Contact Form 7 has a lot of hooks but very little documentation for developers, and most forum threads asking how to use them go unanswered. I first wrote this guide in 2012 while building a plugin that customised how forms were handled, and many of you have used it since. The plugin has changed a lot, so I’ve rewritten it for Contact Form 7 6.x, checking every hook and example against the plugin’s source code.
Upgrading from old code? The 2012 examples accessed properties like $contact_form->posted_data and $contact_form->mail directly and used on_sent_ok to redirect. None of that works anymore: use WPCF7_Submission, prop() and set_properties(), and the JavaScript events shown below.
This isn’t about fixing emails that don’t arrive or styling the form; that’s usually server configuration or CSS. It’s about the Contact Form 7 hooks and how to use them from your own WordPress plugin.
Contact Form 7 hooks at a glance
| Hook | Type | When it runs | Arguments |
|---|---|---|---|
wpcf7_before_send_mail |
Action | After validation and the spam check, just before the email is sent | $contact_form, &$abort, $submission |
wpcf7_mail_sent |
Action | After the email is sent successfully | $contact_form |
wpcf7_mail_failed |
Action | When sending the email fails | $contact_form |
wpcf7_submit |
Action | After every submission, whatever the outcome (sent, invalid, spamā¦) | $contact_form, $result |
wpcf7_after_save |
Action | When a form is saved in the admin (also wpcf7_after_create and wpcf7_after_update) |
$contact_form |
wpcf7_posted_data |
Filter | When the submitted data is collected, before validation | $posted_data |
wpcf7_validate_{type} |
Filter | When validating each field of that type (text, email*, telā¦) |
$result, $tag |
wpcf7_spam |
Filter | When deciding whether a submission is spam | $spam, $submission |
wpcf7_skip_mail |
Filter | Just before sending, to skip the email | $skip_mail, $contact_form |
wpcf7_mail_components |
Filter | When building the email (subject, sender, body, recipient, headers, attachments) | $components, $contact_form, $mail |
wpcf7_editor_panels |
Filter | When building the tabs of the form editor in the admin | $panels |
Creating a WordPress plugin for your hooks
You need to know some PHP and have access to your server’s files. Create a .php file in /wp-content/plugins/, paste this in and enable it in the WordPress dashboard:
<?php
/*
Plugin Name: Contact Form 7 customisations
Description: My Contact Form 7 hooks
Version: 1.0
*/
add_action( 'wpcf7_before_send_mail', 'my_cf7_before_send_mail', 10, 3 );
function my_cf7_before_send_mail( $contact_form, &$abort, $submission ) {
// Our code will go here
}
Note the 10, 3 in add_action(): it tells WordPress to pass all three arguments to your function. The & before $abort passes it by reference, so setting it to true inside your function actually stops the email.
Reading the submitted data
Since Contact Form 7 4.x the submitted values live in a separate WPCF7_Submission object, not in the contact form. In wpcf7_before_send_mail you get it as the third argument; in any other hook, get it with WPCF7_Submission::get_instance():
$submission = WPCF7_Submission::get_instance();
if ( $submission ) {
$data = $submission->get_posted_data(); // all fields as an array
$email = $submission->get_posted_data( 'email' ); // a single field, by its name
$files = $submission->uploaded_files(); // file uploads
$ip = $submission->get_meta( 'remote_ip' ); // also 'url', 'user_agent', 'timestamp'
}
The form itself (WPCF7_ContactForm) gives you id(), title() and its settings through prop(), for example $contact_form->prop( 'mail' ) for the email template.
Contact Form 7 hook examples
Change the email recipient depending on an answer (wpcf7_before_send_mail)
Read the email template with prop(), change it and save it back with set_properties() before it’s sent:
function my_cf7_before_send_mail( $contact_form, &$abort, $submission ) {
$mail = $contact_form->prop( 'mail' );
$department = $submission->get_posted_data( 'department' );
if ( is_array( $department ) ) { // select, radio and checkbox values are arrays
$department = reset( $department );
}
if ( 'Sales' === $department ) {
$mail['recipient'] = 'Sales <[email protected]>';
} else {
$mail['recipient'] = 'Support <[email protected]>';
}
$contact_form->set_properties( array( 'mail' => $mail ) );
}
For a fixed list of recipients you don’t need code: separate them with commas in the To field of the Mail tab.
Stop the email from being sent
Set $abort to true in wpcf7_before_send_mail. Optionally set the message the visitor sees:
if ( '[email protected]' === $submission->get_posted_data( 'email' ) ) { $abort = true; $submission->set_response( 'This address can\'t be used.' ); }
If you only want to skip the email but still treat the submission as successful (for example because you’re saving it somewhere else), use the wpcf7_skip_mail filter instead, or add skip_mail: on to the form’s Additional Settings:
add_filter( 'wpcf7_skip_mail', function ( $skip_mail, $contact_form ) {
return 123 === $contact_form->id() ? true : $skip_mail;
}, 10, 2 );
Add the visitor’s IP address and page to the email
No code needed: Contact Form 7 has special mail-tags you can put in the Mail tab’s message body, such as [_remote_ip], [_url], [_user_agent], [_date], [_time] and [_post_title]. To add something they don’t cover, append it to the body in wpcf7_before_send_mail:
$mail = $contact_form->prop( 'mail' ); $mail['body'] .= "\n\nSubmitted from: " . $submission->get_meta( 'url' ); $contact_form->set_properties( array( 'mail' => $mail ) );
Send the submission to a CRM or API after the email (wpcf7_mail_sent)
add_action( 'wpcf7_mail_sent', function ( $contact_form ) {
if ( 123 !== $contact_form->id() ) {
return;
}
$submission = WPCF7_Submission::get_instance();
wp_remote_post( 'https://crm.example.com/api/leads', array(
'timeout' => 5,
'body' => array(
'name' => $submission->get_posted_data( 'your-name' ),
'email' => $submission->get_posted_data( 'your-email' ),
),
) );
} );
Use wpcf7_mail_failed the same way to log or alert when sending fails.
Log every submission, whatever the result (wpcf7_submit)
add_action( 'wpcf7_submit', function ( $contact_form, $result ) {
// $result['status']: 'mail_sent', 'mail_failed', 'validation_failed', 'acceptance_missing', 'spam' or 'aborted'
error_log( sprintf( 'CF7 form %d: %s', $contact_form->id(), $result['status'] ) );
}, 10, 2 );
Custom validation for a field (wpcf7_validate_{type})
The filter name ends with the field type, including the asterisk for required fields. For example, only accept company email addresses in a required email field called your-email:
add_filter( 'wpcf7_validate_email*', function ( $result, $tag ) {
if ( 'your-email' === $tag->name ) {
$email = isset( $_POST['your-email'] ) ? sanitize_email( wp_unslash( $_POST['your-email'] ) ) : '';
if ( preg_match( '/@(gmail|hotmail|yahoo)\./i', $email ) ) {
$result->invalidate( $tag, 'Please use your company email address.' );
}
}
return $result;
}, 20, 2 );
Mark submissions as spam (wpcf7_spam)
add_filter( 'wpcf7_spam', function ( $spam, $submission ) {
if ( $spam ) {
return $spam;
}
$message = (string) $submission->get_posted_data( 'your-message' );
return false !== stripos( $message, 'crypto investment' );
}, 10, 2 );
Clean up submitted data before it’s used (wpcf7_posted_data)
add_filter( 'wpcf7_posted_data', function ( $posted_data ) {
if ( isset( $posted_data['your-name'] ) ) {
$posted_data['your-name'] = ucwords( strtolower( $posted_data['your-name'] ) );
}
return $posted_data;
} );
Do something when a form is saved in the admin (wpcf7_after_save)
add_action( 'wpcf7_after_save', function ( $contact_form ) {
// e.g. clear a cache or sync the form settings to another system
delete_transient( 'my_cf7_forms_' . $contact_form->id() );
} );
Add your own tab to the form editor (wpcf7_editor_panels)
Each panel has a title and a callback that receives the form being edited:
add_filter( 'wpcf7_editor_panels', function ( $panels ) {
$panels['my-settings-panel'] = array(
'title' => 'My settings',
'callback' => 'my_cf7_settings_panel',
);
return $panels;
} );
function my_cf7_settings_panel( $contact_form ) {
echo '<h2>My settings</h2>';
echo '<p>Form ID: ' . esc_html( $contact_form->id() ) . '</p>';
}
To save fields you add to that tab, read them from $_POST in wpcf7_after_save and store them yourself, for example as post meta on the form’s ID.
Redirect after sending: JavaScript events
The old on_sent_ok setting was removed. Contact Form 7 now fires DOM events on the form, which you can listen to from your theme’s JavaScript:
document.addEventListener( 'wpcf7mailsent', function ( event ) {
if ( '123' == event.detail.contactFormId ) {
window.location.href = 'https://example.com/thank-you/';
}
} );
The available events are wpcf7beforesubmit, wpcf7submit (always), wpcf7mailsent, wpcf7mailfailed, wpcf7invalid, wpcf7spam, wpcf7unaccepted and wpcf7aborted. event.detail includes contactFormId, unitTag, containerPostId, status, the submitted inputs and the server’s apiResponse.
That’s it!
With these hooks you have full control over what Contact Form 7 does with each submission. If something here doesn’t work with your version, or you need an example I haven’t covered, leave a comment below. For bugs in the plugin itself, the Contact Form 7 support forum is the best place.

43 comments
Awesome post dude. You are going really well in blogging. I like it really much. Keep up the good work !
Thanks for this, very helpful.
Thanks, just what I was looking for.
Just one question, is it possible to output:
$wpcf7_data->mail[‘body’]
but then replace the variables with the posted ones?
in other words, is it possible to get the mail body of the mail 1 or 2 being send?
Hello there,
thanks for the interesting post. It gave me a lot of indication and I was wondering if you can perhaps help me to encapsulate the name of the sender in a session variable I can recall in the subsequent Thank you page.
What I did in my function.php code is
function get_contact_form_details($cf7){
$_SESSION[‘cf7data’] = $cf7->posted_data;
return false;
}
add_action( ‘wpcf7_before_send_mail’, ‘get_contact_form_details’ );
whereas in the thank you page I have this code
Hi,
but nothing appear on screen, like the value has never been stored. Any help?
Thanks
Hi Andrea,
I would suggest you to post your question here: http://wordpress.org/support/plugin/contact-form-7
The author of the plugin itself and thousands of developers will be able to help you faster than myself (I’m quite busy these days).
Cheers
Your post really helped me to add contact form 7 name and email to my email marketing site. Thanks for writing this post.
Thanks for this useful information.
I used your plugin but had problems getting all your snippets of code to work.
Then I realised the ones that use:
$WPCF7_ContactForm->worked, and those that use$wpcf7_data->didn’t work.When I substituted the former for the latter, the other snippets worked as well. Wonderful!
Tony
I Use Contact form 7
add_action('wpcf7_before_send_mail','save_to_the_database'); function save_to_the_database($cf7) { global $wpdb; //declare your varialbes, for example: $id = $cf7->posted_data["id"]; $first_name = $cf7->posted_data["first-name"]; $email_txt = $cf7->posted_data["email-id"]; //echo $ticket_id; $result = $wpdb->get_results( "INSERT INTO databasename (`id`, `firstname`, `emailid`) VALUES ('$id','$first_name','$email_txt')"); }Its work fine , also insert data into database.
Now I have Three Contact Form,
contact-form-7 id="411"contact-form-7 id="412"andcontact-form-7 id="413"How can I trigger
Just perfect, thanks !
Sorry but I’m new to to programming.
Where exactly will I add this codes?
Thanks Xavi this was a huge help. I spent a while searching and this is exactly what I needed.
Thank you, exactly that’s what i’ve been searching for :)
Thank you SO much for this, I’ve been searching everywhere for this. Fantastic post.
Hello Xavier
My contact form title is ‘guide_pvh’
The code is :
title;
//if ($title==’pvh_guide’){
// $wpcf7_data->additional_settings = “on_sent_ok: \”location.replace(‘http://locationcontainernamur.com/blog/’);\””;
//}else{
// $wpcf7_data->additional_settings = “on_sent_ok: \”location.replace(‘http://google.com’);\””;
//}
$wpcf7_data->additional_settings = “on_sent_ok: \”location.replace(‘http://locationcontainernamur.com/blog/’);\””;
}
add_action(“wpcf7_before_send_mail”, “wpcf7_do_something”);
?>
but although CF7 told me that the message was sent, in my code the redirection does not work, you have an idea of the problem?
Hi Xavi, thanks a lot for this excellent post. As one of the (lower end) midweight PHP developer, this is what I needed.
Hello Xavi,
I like to pick your brain: do you know if a CF7 form can have multiple thank-you redirections based on selected form values??
i am testing with a custom function in functions.php but i dont see an appropiate hook.
Any ideas, tips?
Hello barry,
Yes, copy the code at “Redirecting someone to a different page depending on submitted data” but instead of
$foo == "provider"use$_GET['the-select-field-name'] == "option1", etc.You may want put that in a plugin instead of the functions.php, the code at “Creating a WordPress plugin” in the article should work for you.
Cheers,
Xavi
Thank You! I have two CF7 forms and Flamingo installed. Would this be a way I can prevent one of the forms from being saved in the database from the Flamingo plugin?
Hi Laura, I can’t tell for sure but it should. Try returning an empty variable for
$WPCF7_ContactForm.Hi Xavi,
Would this not work if write this in functions.php file ?
Hi Sohail,
It will, just make sure to call it through the hook (
add_action…).“WordPress Contact 7 , make Conditional Email Body ??”
Hello i am using Contact 7 form plugin. I get option to have HTML body for email template like
Name:
[your-name]
Here [your-name] is actually value of textbox,I Dont want to make REQUIRED field,
So what i want is IF THE NAME TEXT BOX VALUE is filled only then show labels and textbox value.Means show the above given Table in email ONLY IF IT IS FILLED .
I searched a lot ,i didnt get any help on any website ,Please help me .Thanks
Hi Pratik,
The email is in this variable:
$wpcf7_data->mail['body']so you can modify it freely. You can even empty it and start filling it conditionally:$wpcf7_data->mail['body'] = ""; if ($wpcf7_data->posted_data['your-name']) { $wpcf7_data->mail['body'] .= "Hello [your-name]!"; }untested code
Hi Xavi,
I like to redirect when email is not successfully send. Have you got an idea for this? Thanks, Remco
Hi Xavi,
I’m new to wordpress so I’m having some issues.
I need to change the recipient mail address based on a parameter that is called $citta (it means city)and is in the url of the page where the form is (ex. http://www.test.com?citta=Florence). So, if $citta is equal to Rome the form must send to a certain address and so on.
I created a plugin following your tutorial but when I compile the form it does not send anything.
Could you possibly check my code? Thank you so much.
A last question: what should I write in the recipient (To) field in Contact form editing page? I wrote [recipient] but I am not sure about it.
function wpcf7_do_something (&$WPCF7_ContactForm) {
if ($citta == “Rome”) {
$WPCF7_ContactForm->mail[‘recipient’] = “Rome “;
}
if ($citta == “Turin”) {
$WPCF7_ContactForm->mail[‘recipient’] = “Turin “;
}
if ($citta == “Florence”) {
$WPCF7_ContactForm->mail[‘recipient’] = “Florence “;
}
}
add_action(“wpcf7_before_send_mail”, “wpcf7_do_something”);
FYI, this code will need to be updated to reflect the latest version of WPCF7 (3.9)… The access to the posted data has changed. See: http://contactform7.com/2014/07/02/contact-form-7-39-beta/
This was code example was causing headaches when posted_data was NULL… see link on how to access data.
Hey thanks Xavi for this wonderful article..
Though it did not solved my problem but I was able to manage to catch the tweak required for adding this data to salesforce CRM and was successful.
I had to replace $wpcf7_data->posted_data[‘your-name’] with $POST[‘your-name’] to get the data of form fields.. else it was all coming blank variables.
Anyways, Thanks for the post.
Good Luck.
Wanted to say thanks. With the new release at http://contactform7.com/2014/07/02/contact-form-7-39-beta/ I wanted to mention that some of these have changed. Until I found that reference it was a little bit of a pain to debug!
For example a new URL redirect is
Thanks a lot Vir J and Andrew, I’ll update the post ASAP.
Hi Thanks for the post. Just a heads up apparently the original developer has changed the way how you can get and modify the posted data in contact form 3.9. If you would like you can look the link here: http://contactform7.com/2014/07/02/contact-form-7-39-beta/
Hi Xavi,
When can we expect the ASAP update? I’m trying to use your code, but it’s not working with the new version of CF7.
Passing the form object by reference in the function breaks feedback messages, though the message itself is sent through no worries
Superb, Thanks for this code
I want to create an form who will send email based on option selected from radio. Is it possible using contact form 7?
Whenever I activate my plugin the whole code is displayed on every single page of my website. Right above the actual content. What could that be?
Hi Xavi,
I m new in wp. I want to add two more fields in contact form and i m blind to do that. 1st I want to add date of birth which should use regex to check whether person is 18 yrs old or not.
2nd I want to add Security number which again require some restrictions. can u help me plz I will be really thankful to u
Cheers for this saved me a few hours researching :)
Thumbs up!
Thanks for the article, i have a page with multiple forms and i’m am trying to send an event to analytics after a form is sent successfully.
The thing is that i need a different event for each form, how can i get the form id (after submission) using PHP ?
Hellow
First of all sorry about my english ( im from Southamerica )
I have a question ..
I have CF7 and i made a form , i need to change the subject of the email.
For example: In the label Subject i used mail-tags like this
“Email from the website – [nameperson] [lastname] [phonenumber]”
The mail-tags works fine, but i want that the name and the lastname arrives in a capitalize format.
Like this:
“Email from the website – Hector Johnson 8238832”
The problem is that the subject of the mail is like this.
“Email from the website – hector johnson 8238832”
I need a hook to change this please .. please help me with this issue.
Thanks
Hello. Please help. Added this code to the file:
add_action(‘wpcf7_before_send_mail’,’printDatas’);
function printDatas($cf7) {
global $wpdb;
//declare your varialbes, for example:
$id = $cf7->posted_data[“id”];
$first_name = $cf7->posted_data[“your-name”];
$email_txt = $cf7->posted_data[“email-id”];
}
In the template file I added this code: do_action(‘wpcf7_before_send_mail’);
Did a redirect in the advanced settings of the Contact Form 7 did a redirect to the page where you display the data. But nothing is displayed what is the error?
Sorry
add_action(āwpcf7_before_send_mailā,āprintDatasā);
function printDatas($cf7) {
global $wpdb;
//declare your varialbes, for example:
$id = $cf7->posted_data[āidā];
$first_name = $cf7->posted_data[āyour-nameā];
$email_txt = $cf7->posted_data[āemail-idā];
echo $first_name;
echo $email_txt;
}
hi,
i am not able to understand how to trigger after submit form, to send sms on form mobile number.