March 11, 2020: Fixed issue where target and source field were mixed up. How did this bug exist for so long!?
October 5, 2019: Fixed issue where AJAX validation was not working correctly when specifying fields via the
field_map
property.February 7, 2017: Fixed issue where submitting the form before AJAX validation had completed resulted in a failure to capture the target field's value.
February 6, 2017: Fixed two issues with validation; validation did not work correctly on submission; AJAX validation was not validating against the correct source field ID.
February 5, 2017: Added support for AJAX validation; value is validated as soon as the user exits the input.
August 29, 2016: Updated article with documentation for "field_map" parameter.
May 14, 2015: Updated does_value_exist() method to only query active entries.
<?php | |
/** | |
* Gravity Wiz // Gravity Forms // Validate that a Value Exists | |
* | |
* Ensure that a value entered in Form A has been previously submitted on Form B. This is useful if you're generating a reference number of some sort | |
* on Form B and would like the user to enter it on Form A. | |
* | |
* @version 1.8 | |
* @author David Smith <david@gravitywiz.com> | |
* @license GPL-2.0+ | |
* @link http://gravitywiz.com/... | |
*/ | |
class GW_Value_Exists_Validation { | |
protected static $is_script_output = false; | |
public function __construct( $args = array() ) { | |
// set our default arguments, parse against the provided arguments, and store for use throughout the class | |
$this->_args = wp_parse_args( $args, array( | |
'target_form_id' => false, | |
'target_field_id' => false, | |
'source_form_id' => false, | |
'source_field_id' => false, | |
'validation_message' => __( 'Please enter a valid value.' ), | |
'field_map' => array(), | |
'disable_ajax_validation' => false | |
) ); | |
// Map source and target fields to field map if field map is not set. | |
if( empty( $this->_args['field_map'] ) ) { | |
$this->_args['field_map'] = array( $this->_args['source_field_id'] => $this->_args['target_field_id'] ); | |
} | |
// do version check in the init to make sure if GF is going to be loaded, it is already loaded | |
add_action( 'init', array( $this, 'init' ) ); | |
} | |
public function init() { | |
// make sure we're running the required minimum version of Gravity Forms | |
if( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) ) { | |
return; | |
} | |
add_filter( 'gform_validation', array( $this, 'validation' ) ); | |
if( ! $this->_args['disable_ajax_validation'] ) { | |
add_action( 'gform_enqueue_scripts', array( $this, 'enqueue_form_script' ) ); | |
add_filter( 'gform_pre_render', array( $this, 'load_form_script' ), 10, 2 ); | |
add_action( 'gform_register_init_scripts', array( $this, 'add_init_script' ) ); | |
add_action( 'wp_ajax_gwvev_does_value_exist', array( $this, 'ajax_does_value_exist' ) ); | |
add_action( 'wp_ajax_nopriv_gwvev_does_value_exist', array( $this, 'ajax_does_value_exist' ) ); | |
} | |
} | |
public function enqueue_form_script( $form ) { | |
if( $this->is_applicable_form( $form ) ) { | |
wp_enqueue_script( 'gform_gravityforms' ); | |
} | |
return $form; | |
} | |
public function validation( $result ) { | |
if( ! $this->is_applicable_form( $result['form'] ) ) { | |
return $result; | |
} | |
foreach( $result['form']['fields'] as &$field ) { | |
if( $this->is_applicable_field( $field ) && ! GFFormsModel::is_field_hidden( $result['form'], $field, array() ) ) { | |
if( ! $this->do_values_exists( $this->get_values(), $this->_args['source_form_id'] ) ) { | |
$field['failed_validation'] = true; | |
$field['validation_message'] = $this->_args['validation_message']; | |
$result['is_valid'] = false; | |
} | |
} | |
} | |
return $result; | |
} | |
public function ajax_does_value_exist() { | |
if( ! wp_verify_nonce( rgpost( 'nonce' ), 'gwvev_does_value_exist' ) ) { | |
die( __( 'Invalid nonce.' ) ); | |
} | |
$form_id = rgpost( 'form_id' ); | |
$input_id = rgpost( 'input_id' ); | |
$value = rgpost( 'value' ); | |
$entries = $this->get_matching_entry( array( $input_id => $value ), $form_id ); | |
echo json_encode( array( | |
'doesValueExist' => ! empty( $entries ), | |
'entries' => $entries, | |
) ); | |
die(); | |
} | |
public function does_value_exist( $value, $form_id, $field_id ) { | |
$entries = $this->get_matching_entry( array( $field_id => $value ), $form_id ); | |
return count( $entries ) > 0; | |
} | |
public function do_values_exists( $values, $form_id ) { | |
$entries = $this->get_matching_entry( $values, $form_id ); | |
return $entries && count( $entries ) > 0; | |
} | |
public function get_matching_entry( $values, $form_id ) { | |
$field_filters = array(); | |
foreach( $values as $field_id => $value ) { | |
$field_filters[] = array( | |
'key' => $field_id, | |
'value' => $value | |
); | |
} | |
$entries = GFAPI::get_entries( $form_id, array( 'status' => 'active', 'field_filters' => $field_filters ) ); | |
return reset( $entries ); | |
} | |
public function get_field_map() { | |
if( ! empty( $this->_args['field_map'] ) ) { | |
$field_map = $this->_args['field_map']; | |
} else { | |
$field_map = array( $this->_args['target_field_id'] => $this->_args['source_field_id'] ); | |
} | |
return $field_map; | |
} | |
public function get_values() { | |
$field_map = $this->get_field_map(); | |
$values = array(); | |
foreach( $field_map as $source_field_id => $target_field_id ) { | |
$value = rgpost( 'input_' . $target_field_id ); | |
if( $value ) { | |
$values[ $source_field_id ] = $value; | |
} | |
} | |
return $values; | |
} | |
public function load_form_script( $form, $is_ajax_enabled ) { | |
if( $this->is_applicable_form( $form ) && ! self::$is_script_output && ! $this->is_ajax_submission( $form['id'], $is_ajax_enabled ) ) { | |
$this->output_script(); | |
} | |
return $form; | |
} | |
public function output_script() { | |
?> | |
<script type="text/javascript"> | |
( function( $ ) { | |
window.GWValueExistsValidation = function( args ) { | |
var self = this; | |
// copy all args to current object: (list expected props) | |
for( prop in args ) { | |
if( args.hasOwnProperty( prop ) ) { | |
self[ prop ] = args[ prop ]; | |
} | |
} | |
self.init = function() { | |
$( self.selectors.join( ', ' ) ).on( 'change', function() { | |
var inputId = gf_get_input_id_by_html_id( $( this ).attr( 'id' ) ); | |
for( var sourceFieldId in self.fieldMap ) { | |
if( self.fieldMap.hasOwnProperty( sourceFieldId ) && sourceFieldId == inputId ) { | |
break; | |
} | |
} | |
self.doesValueExist( inputId, sourceFieldId, $( this ).val(), $( this ) ); | |
} ); | |
}; | |
self.doesValueExist = function( inputId, sourceFieldId, value, $elem ) { | |
if( ! value ) { | |
return; | |
} | |
var spinner = new self.spinner( $elem, false, 'position:relative;top:2px;left:-25px;' ), | |
responseHtmlId = 'response_{0}_{1}'.format( self.targetFormId, inputId), | |
$buttons = $( '.gform_button' ); | |
$buttons.prop( 'disabled', true ); | |
$elem.prop( 'disabled', true ); | |
$( '#' + responseHtmlId ).remove(); | |
$.post( self.ajaxUrl, { | |
nonce: self.nonce, | |
action: 'gwvev_does_value_exist', | |
input_id: sourceFieldId, | |
value: value, | |
form_id: self.sourceFormId | |
}, function( response ) { | |
$elem.prop( 'disabled', false ); | |
$buttons.prop( 'disabled', false ); | |
spinner.destroy(); | |
if( ! response ) { | |
return; | |
} | |
var template = '<span id="{0}" class="gwvev-response {1}">{2}</span>'; | |
response = $.parseJSON( response ); | |
if( response.doesValueExist ) { | |
$elem.after( template.format( responseHtmlId, 'gwvev-response-success', '✔' ) ); | |
} else { | |
$elem.after( template.format( responseHtmlId, 'gwvev-response-error', '✘' ) ); | |
} | |
gform.doAction( 'gwvev_post_ajax_validation', self, response ); | |
} ); | |
}; | |
self.spinner = function( elem, imageSrc, inlineStyles ) { | |
imageSrc = typeof imageSrc == 'undefined' || ! imageSrc ? self.gfBaseUrl + '/images/spinner.gif': imageSrc; | |
inlineStyles = typeof inlineStyles != 'undefined' ? inlineStyles : ''; | |
this.elem = elem; | |
this.image = '<img class="gfspinner" src="' + imageSrc + '" style="' + inlineStyles + '" />'; | |
this.init = function() { | |
this.spinner = jQuery(this.image); | |
jQuery(this.elem).after(this.spinner); | |
return this; | |
}; | |
this.destroy = function() { | |
jQuery(this.spinner).remove(); | |
}; | |
return this.init(); | |
}; | |
self.init(); | |
} | |
} )( jQuery ); | |
</script> | |
<?php | |
self::$is_script_output = true; | |
} | |
public function add_init_script( $form ) { | |
if( ! $this->is_applicable_form( $form ) ) { | |
return; | |
} | |
$args = array( | |
'ajaxUrl' => admin_url( 'admin-ajax.php' ), | |
'nonce' => wp_create_nonce( 'gwvev_does_value_exist' ), | |
'targetFormId' => $this->_args['target_form_id'], | |
'sourceFormId' => $this->_args['source_form_id'], | |
'selectors' => $this->get_selectors( $form ), | |
'fieldMap' => $this->get_field_map(), | |
'gfBaseUrl' => GFCommon::get_base_url(), | |
); | |
$script = 'new GWValueExistsValidation( ' . json_encode( $args ) . ' );'; | |
$slug = implode( '_', array( 'gw_value_exists_validation', $this->_args['target_form_id'], $this->_args['target_field_id'] ) ); | |
GFFormDisplay::add_init_script( $this->_args['target_form_id'], $slug, GFFormDisplay::ON_PAGE_RENDER, $script ); | |
} | |
public function get_selectors( $form ) { | |
$selectors = array(); | |
foreach( $form['fields'] as $field ) { | |
if( ! $this->is_applicable_field( $field ) ) { | |
continue; | |
} | |
$prefix = sprintf( '#input_%d_%d', $form['id'], $field->id ); | |
if( is_array( $field->inputs ) ) { | |
foreach( $field->inputs as $input ) { | |
$bits = explode( '.', $input['id'] ); | |
$input_id = $bits[1]; | |
$selectors[] = "{$prefix}_{$input_id}"; | |
} | |
} else { | |
$selectors[] = $prefix; | |
} | |
} | |
return $selectors; | |
} | |
public function is_applicable_form( $form ) { | |
$form_id = isset( $form['id'] ) ? $form['id'] : $form; | |
return $form_id == $this->_args['target_form_id']; | |
} | |
public function is_applicable_field( $field ) { | |
$field_map = $this->get_field_map(); | |
return $this->is_applicable_form( $field->formId ) && in_array( $field->id, $field_map ); | |
} | |
public function is_ajax_submission( $form_id, $is_ajax_enabled ) { | |
return isset( GFFormDisplay::$submission[ $form_id ] ) && $is_ajax_enabled; | |
} | |
} | |
# Configuration | |
new GW_Value_Exists_Validation( array( | |
'target_form_id' => 123, | |
'target_field_id' => 1, | |
'source_form_id' => 124, | |
'source_field_id' => 1, | |
'validation_message' => 'Hey! This isn\'t a valid reference number.' | |
) ); |
Let’s say a reference number is generated on Form A (using something like GP Unique ID) for the user’s order (represented by a Gravity Form entry). The reference number is emailed to the user.
On Form B, the user is able to contact you about their order by entering the reference number. If they fail to enter a valid reference number, a validation error is returned and they are unable to submit the form.
How to Generate and Validate a Reference Number for Gravity Forms with GP Unique ID
Getting Started
- Check requirements
- Make sure you have Gravity Forms installed and activated.
- Already have a license? Download Latest Gravity Forms
- Need a license? Buy Gravity Forms
- Make sure you have Gravity Forms installed and activated.
- Install the snippet
- Copy and paste the entire snippet into your theme’s functions.php file.
Configure the snippet
Once you have installed the snippet, look at the bottom of the snippet for this block of code:
new GW_Value_Exists_Validation( array( 'target_form_id' => 123, 'target_field_id' => 1, 'source_form_id' => 124, 'source_field_id' => 1, 'validation_message' => 'Hey! This isn\'t a valid reference number.' ) ); - The target form ID and field ID represent the form and field that should be validated and show the validation error when validation fails.
- The source form ID and field ID represent the form and field that store the existing value that the value submitted in the target form and field should be checked against.
- The validation message can be updated to any message you would like to indicate that the entered value did not match any existing values in the source form and field.
Parameters
target_form_id (integer) (required)
This is the Form ID for the field that you will checking if a value already exists (Form B in the example above). There is no default value.
target_field_id (integer) (required)
This is the Field ID for the field that you will checking if a value already exists (Form B in the example above). There is no default value.
source_form_id (integer) (required)
This is the Form ID for the field that generated the reference number (Form A in the example above). There is no default value.
source_field_id (integer) (required)
This is the Field ID for the field that generated the reference number (Form A in the example above). There is no default value.
validation_message (string) (optional)
This is the error message that will be displayed if the value being tested does not already exist. Defaults to
"Hey! This isn't a valid reference number."
field_map (array) (optional)
An array of target and source field IDs; allows for creating multiple requirements that must match the same entry. Format should be:
array( // TARGET_FIELD_ID1 => SOURCE_FIELD_ID1, 2 => 3, 5 => 11 );
disable_ajax_validation (bool) (optional)
Optionally disable AJAX validation. AJAX validation is enabled by default and will add a checkmark or an x-mark depending on whether the value exists.
Any questions?
This snippet is more of a building block rather than a final solution. Let us know how you’re using it and any questions you have about building on top of it to accomplish a more involved solution.
For an example of how this can be combined with other plugins to create a more robust solution, check out the How to Generate and Validate a Reference Number for Gravity Forms with GP Unique ID tutorial.
We hope you find this snippet useful! If you do, show us some love by sharing this article on the social media platform of your choice. Let’s keep the Gravity Wiz pumping out awesome snippets.
Did this resource help you do something awesome with Gravity Forms? Then you'll absolutely love Gravity Perks; a suite of 32+ essential add-ons for Gravity Forms with support you can count on.
I have a theoretical question. I’m using Gravity Forms for support tickets, but only certain websites are eligible for support. I want to validate their website. Could I create a user registration form (Form A) where they put in their website address and then use that form as a source of validation that their website is covered on Form B? Also, lets say their support coverage ends on that website, would I need to delete the entry in Form A, or could I use the field_map parameter to look at a field in Form A that shows whether that website’s support is active?
Hi Brandon,
Your solution looks like a good one and it should work perfectly for what you want to achieve. Form A, which is the user registration form will contain the entries with website addresses that Form B will use to check if a User’s website is eligible for support. Currently, you’ll have to delete an entry if a user’s support coverage ends. However, if you’ll want to keep those entries when the support coverage ends, a workaround will be to manually append a text to the website URL on the Entry page, so that when a user enters it in Form B, there wouldn’t be a match.
Best,
Hi,
How would I go about using the snippet for multiple forms. Example: I want to validate field id 1 in form 1 against field id 2 in form 2, but then I also want to validate field id 1 in from 3 with field id 2 in form 4. So basically more than 1 source id and target id. I tried to copy the code twice in functions.php and renaming the class and some of the functions, but looks like it calls the init of the first.
Thanks, Marcel
Hey Marcel, check out our article here https://gravitywiz.com/documentation/apply-class-based-snippet-different-forms/ on how to add multiple instances to your same function. Let us know if you have any other questions.
Hi,
this does not seem to work across forms,but only when source and target form ids are the same…. is there a bug?
Thanks, Marcel
Hello Marcel, make sure you’ve installed it correctly to start: https://gravitywiz.com/documentation/snippet-troubleshooting/ The demo is still working so this is likely a configuration issue. If you are still having the issue let us know what version of WordPress and Gravity Forms you are using.
How would I add a date condition to the validation? So not only does the code but it validates the date as well. For example it validates the code and also the date_created against the current date. Where the current date is not more than 3 days from the date_created.
Anyone have any ideas?
Hi Churmi,
This may be possible with some changes to the snippet, but unfortunately, we are unable to assist with snippet customizations at the moment.
Best,
while enabling this script, the “Skip Pages on Multi-Page Forms” script is not functioning
Hello Jasim, could you please let us know which snippet you are refering to? Thanks!
While adding “Multi Page Auto Advance for Gravity Forms” https://gravitywiz.com/require-existing-value-submission-gravity-forms/ snippet to the theme config.php, the “Skip Pages on Multi-Page Form” https://gravitywiz.com/pro-tip-skip-pages-on-multi-page-forms/ snippet stop working
sorry function.php – not config.php
Hello Jasim, I just tested this out on my test server and cannot recreate this issue. Both snippets are working perfectly fine with one another. Are you adding ?form_page=2 at the end of your URL? What seems to be the issue? Could you run a theme/conflict test?
Will this work to cross validate between forms? Example: Check if name and dob exists from form a to form b.
Thanks
The snippet is not working for me and I am unable to determine why. HELP
Hi Kimberly, make sure you’ve installed it correctly to start: https://gravitywiz.com/documentation/snippet-troubleshooting/ The demo is still working so this is likely a configuration issue.
Looking for help to use this snippet Hey can you we validate to target ids in the form A with one source id in Form B ? if yes what changes need to be done in the code above?
Not sure I understand, Hammal?
@David. I mean I want to validate the code in two different places in form A and both the code as the same source Form B how can I do that.
I can modify for the user only have access to the form if the payment of woocommerce is marked “Completed”?
Hm, I don’t have a ready solution for this one.
Hi, Thanks for your previous reply. Is it possible to have multiple instances of this snippet e.g. for two separate forms? Can you explain how? Thanks!
1) Same question as Adesola 2) Can I validate against the “Entry ID” field? how do I get the ID of that field? Thanks!
Looks like you can just set “id” as your “source_field_id” parameter. Something like this worked for me: http://snippi.com/s/46u74sr
Hello david, how do I bulk generate unique membership Ids for users that had already submitted entries before the unique ID field was added to the form?
Hi David, I found your script and I wonder if it can be a base for a solution from my task. I tried to customize the script, but it does not work. Is there a chance to help me?
May task: I have 3 relevant fields: 1: username 2: projectnumber 3: shared username
If a user creates an entry to be searched if the same number already exists in another entry. If the number already exists the username of the first user should be entered in field 3. The reason is the following: it is allowed to use identical numbers multiple times. but the users should be shown, which user has already used these identical numbers.
Kind Regards Michael
Hi Michael, unfortunately, we just don’t have the throughput to help out with snippet customizations. :/
Hi, Thank you for your great effort. I tried to use it and it did work however when i try to use the field_map, it doesn’t stick to the pointed source_field_id only but it also accepts any entries from other fields ids if the entered value matches. My example below: the field id 12 – form 18 should only validated through field id 5 – form id 17 and the field id 6 – form 18 should only validated through field id 3 – form id 17 but what happens is that if the entered value in field 12 matches an entry value at field id 3 it marks it as valid and continue and same for field id 6 and source field id 5.
Please help.
Thanks in advance
Trying removing these lines form the configuration:
‘target_field_id’ => ” ‘source_field_id’ => ”