Preventing Duplicate Submissions from CF7
Situation: You have users who submit forms but you don’t want them to submit more than once.
Solution: add a custom validation to a form field that uniquely identifies the submission.
This solution is for Contact Form 7. Contact Form 7 has a hook into which you can inject custom validation code. It is somewhat limited, so read carefully.
Let’s assume that essentially what you need to do is prevent users from submitting a form more than once with the same email address it in. In this example, we will put a validation on one particular form field and check if that email was submitted previously. We will ignore all other fields in this example.
The limitation to the Contact Form 7 field validation is that although we can put in code to validate a particular field, in that code we can’t know what form the submission is coming from. This means that if you set up a validation on a field named “email” then that validation will be run against all form submissions that have an “email” field. If you have more than one form with a field named “email” but you only want this validation run for one particular form, then you have a problem.
The best idea is to give a unique name to the email field in your form. Use this name only on this form and none other. In this example, we we “email_123″.
To create the validation, we add WordPress filter code into Tools -> Add Actions and Filters provided by the “Add Actions and Filters” plugin. This is the same technique used in Changing Form Data Before it is Saved.
The following code is an example. You will need to make some changes to make it work for you. In the my_validate_email function:
- Change $formName to the name of your form
- Change $fieldName to the name of your email field
- Optionally change the error message
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | function is_already_submitted($formName, $fieldName, $fieldValue){ require_once(ABSPATH . 'wp-content/plugins/contact-form-7-to-database-extension/CFDBFormIterator.php'); $exp = new CFDBFormIterator(); $atts = array(); $atts['show'] = $fieldName; $atts['filter'] = "$fieldName=$fieldValue"; $exp->export($formName, $atts); $found = false; while ($row = $exp->nextRow()) { $found = true; } return $found; } function my_validate_email($result, $tag) { $formName = 'email_form'; // Name of the form containing this field $fieldName = 'email_123'; // Set to your form's unique field name $name = $tag['name']; if($name == $fieldName){ $valueToValidate = $_POST[$name]; if (is_already_submitted($formName, $fieldName, $valueToValidate)) { $result['valid'] = false; $result['reason'][$name] = 'Email has already been submitted'; // error message } } return $result; } add_filter('wpcf7_validate_email*', 'my_validate_email', 10, 2); |
If you field is not an email field, use ‘wpcf7_validate_text‘ instead of ‘wpcf7_validate_email‘, e.g.:
29 | add_filter('wpcf7_validate_text*', 'my_validate_email', 10, 2); |
(Thanks to a user for pointing this out)
I am trying to check 2 fields: email and licenseplate. I there a way to do that?
You can check them individually but not as a a set.
The CF7 validation is done independently for each individual field. This is “field level validation” and there is no available “form level validation.” I encourage you to post on the CF7 forum to request this feature.
To check both fields (independently)
1. make two copies of the my_validate_email function, giving each a different name.
In each:
1.1. Give each one a different $fieldName.
1.2. Update the error message
2. Provide 2 add_filter function calls, one to to register each of those functions (change the 2nd argument to function names in (1))
Thanks for the response. I tried it and it didn’t work, I think number 2 I am confused about.
Here is what I have:
[code]function is_already_submitted($formName, $fieldName, $fieldValue){
require_once(ABSPATH . 'wp-content/plugins/contact-form-7-to-database-extension/CFDBFormIterator.php');
$exp = new CFDBFormIterator();
$atts = array();
$atts['show'] = $fieldName;
$atts['filter'] = "$fieldName=$fieldValue";
$exp->export($formName, $atts);
$found = false;
while ($row = $exp->nextRow()) {
$found = true;
}
return $found;
}
function my_validate_email($result, $tag) {
$formName = 'Free Wash'; // Name of the form containing this field
$fieldName = 'email'; // Set to your form's unique field name
$name = $tag['name'];
if($name == $fieldName){
$valueToValidate = $_POST[$name];
if (is_already_submitted($formName, $fieldName, $valueToValidate)) {
$result['valid'] = false;
$result['reason'][$name] = 'Email has already been submitted'; // error message
}
}
return $result;
}
function my_validate_license($result, $tag) {
$formName = 'Free Wash'; // Name of the form containing this field
$fieldName = 'licenseplate'; // Set to your form's unique field name
$name = $tag['name'];
if($name == $fieldName){
$valueToValidate = $_POST[$name];
if (is_already_submitted($formName, $fieldName, $valueToValidate)) {
$result['valid'] = false;
$result['reason'][$name] = 'License Plate has already been submitted'; // error message
}
}
return $result;
}
add_filter('wpcf7_validate_email', 'my_validate_email', 10, 2);
add_filter('wpcf7_validate_email', 'my_validate_license', 10, 2);
[/code]
Figured it out, the above code is right except this line
add_filter(‘wpcf7_validate_email’, ‘my_validate_license’, 10, 2);
should be
add_filter(‘wpcf7_validate_text’, ‘my_validate_license’, 10, 2);
Thanks for the help
Another Question on this script.
Is there away to ignore the case when comparing values in this script?
Thanks
Jeff
@Jeff Frey
What case? I don’t follow.
One of the fields we are checking is a license plate number. We need when checked it doesn’t look at upper letter as different form lower case letters.
Sorry could have explained that better the first time.
Thanks for your help.
Try using regex in the filter:
Thanks Michael,
It works perfect.
I appreciate all your help!
Hope this helps others as well.
Thanks again.
Hi;
I want to validate the submission of only one national document number in the form.
I try to submit same document but the functions do not detect it.
I try with the default WP theme.
It is a required field, and I try with the following code too:
add_filter(‘wpcf7_validate_text*’, ‘my_validate_email’, 10, 2);
Anything else to try?
Thanks!!!
A thought: the “wpcf7_validate_text” is hooked into CF7 text fields. If you are trying to validate a different kind of field, then you might need a different hook name. Use the debug technique to print out something to see if your function is even called.