gform_field_validation

Description

Use this filter to create custom validation logic for a field.

Usage

The base filter which applies to all forms and all fields would be used like so:

add_filter( 'gform_field_validation', 'your_function_name', 10, 4 );

You can also target all fields in a form by adding the form id after the hook name.

// The following declaration targets all fields in form 6
add_filter( 'gform_field_validation_6', 'your_function_name', 10, 5 );

You can also target a specific field by adding the form id and field id after the hook name.

// The following declaration targets field 1 in form 6
add_filter( 'gform_field_validation_6_1', 'your_function_name', 10, 5 );

Parameters

  • $result array The validation result to be filtered. It is formatted as follows:
array( 'is_valid' => false, 'message' => 'Please enter a number greater than 10' )
  • $value string | array The field value to be validated. Multi-input fields like Address will pass an array of values.
  • $form Form Object Current form object.
  • $field Field Object Current field object.
  • $context string The context for the current submission. Since Gravity Forms 2.6.3.2. Possible values: form-submit, api-submit, or api-validate.

Examples

Number field validation

This example validates a field so that only numbers less than 10 are allowed.

add_filter( 'gform_field_validation_175_1', 'custom_validation', 10, 4 );
function custom_validation( $result, $value, $form, $field ) {
 
    if ( $result['is_valid'] && intval( $value ) > 10 ) {
        $result['is_valid'] = false;
        $result['message'] = 'Please enter a value less than 10';
    }
    return $result;
}

User Defined Price field validation

This example validates an User Defined Price field to make sure the user entered an amount of at least 0.50. The example targets a field with id 23 in a form with id 96, update the filter name with your field and form id or remove them to target all User Defined Price fields in all forms.

add_filter( 'gform_field_validation_96_23', 'gf_user_defined_price_validation', 10, 4 );
function gf_user_defined_price_validation( $result, $value, $form, $field ) {
    //change value for price field to just be numeric (strips off currency symbol, etc.) using Gravity Forms to_number function
    //the second parameter to to_number is the currency code, ie "USD", if not specified USD is used
    $number = GFCommon::to_number( $value, '' );
	GFCommon::log_debug( __METHOD__ . '(): User Defined Price Submitted: ' . $number );
 
    if ( $result['is_valid'] && $number < 0.50 ) {
        $result['is_valid'] = false;
        $result['message'] = 'You must enter at least $0.50';
    }
    return $result;
}

Address field validation

This example validates the address field so that you can control which parts are required. Only the street, city, and state are required in this example.

add_filter( 'gform_field_validation_362_1', 'custom_address_validation', 10, 4 );
function custom_address_validation( $result, $value, $form, $field ) {
	//address field will pass $value as an array with each of the elements as an item within the array, the key is the field id
	if ( 'address' === $field->type && $field->isRequired ) {
		GFCommon::log_debug( __METHOD__ . '(): Running.' );
		//address failed validation because of a required item not being filled out
		//do custom validation
		$street  = rgar( $value, $field->id . '.1' );
		$street2 = rgar( $value, $field->id . '.2' );
		$city    = rgar( $value, $field->id . '.3' );
		$state   = rgar( $value, $field->id . '.4' );
		$zip     = rgar( $value, $field->id . '.5' );
		$country = rgar( $value, $field->id . '.6' );

		//check to see if the values you care about are filled out
		$required_inputs = array( '1' => $street, '3' => $city, '4' => $state );
		$empty_input = false;

		foreach ( $required_inputs as $input_number => $input_value ) {
			GFCommon::log_debug( __METHOD__ . '(): Is Hidden? ' . $field->get_input_property( $input_number, 'isHidden' ) );
			if ( empty( $input_value ) && ! $field->get_input_property( $input_number, 'isHidden' ) ) {
				$field->set_input_validation_state( $input_number, false ); // Only for Gravity Forms 2.5.10 or higher.
				$empty_input = true;
				GFCommon::log_debug( __METHOD__ . "(): Empty input: {$field->id}.{$input_number}" );
			}
		}

		if ( $empty_input ) {
			$result['is_valid'] = false;
			$result['message']  = empty( $field->errorMessage ) ? 'This field is required. Please enter at least a street, city, and state.' : $field->errorMessage;
		} else {
			$result['is_valid'] = true;
			$result['message']  = '';
		}
	}
	GFCommon::log_debug( __METHOD__ . '(): Returning validation result.' );
	return $result;
}

This example validates the zip input of field 1 on form 2.

add_filter( 'gform_field_validation_2_1', 'custom_zip_validation', 10, 4 );
function custom_zip_validation( $result, $value, $form, $field ) {
	if ( $result['is_valid'] ) {
		$acceptable_zips = array(
			'123',
			'456',
		);

		$zip_value = rgar( $value, $field->id . '.5' );

		if ( ! in_array( $zip_value, $acceptable_zips ) ) {
			$field->set_input_validation_state( 5, false ); // Only for Gravity Forms 2.5.10 or higher.
			$result['is_valid'] = false;
			$result['message']  = 'Zip validation failed.';
		}
	}

	return $result;
}

Name field validation

This example validates all the Name field inputs which are not hidden, the default validation only requires the first and last inputs.

add_filter( 'gform_field_validation', function ( $result, $value, $form, $field ) {
	if ( 'name' === $field->type && $field->isRequired ) {
		GFCommon::log_debug( __METHOD__ . '(): Running.' );
		// Input values.
		$prefix = rgar( $value, $field->id . '.2' );
		$first  = rgar( $value, $field->id . '.3' );
		$middle = rgar( $value, $field->id . '.4' );
		$last   = rgar( $value, $field->id . '.6' );
		$suffix = rgar( $value, $field->id . '.8' );

		$name_field = array( '2' => $prefix, '3' => $first, '4' => $middle, '6' => $last, '8' => $suffix );

		foreach ( $name_field as $input_number => $input_value ) {
			if ( empty( $input_value ) && ! $field->get_input_property( $input_number, 'isHidden' ) ) {
				$field->set_input_validation_state( $input_number, false ); // Only for Gravity Forms 2.5.10 or higher.
				$result['is_valid'] = false;
				$result['message']  = empty( $field->errorMessage ) ? __( 'This field is required. Please enter a complete name.', 'gravityforms' ) : $field->errorMessage;
				GFCommon::log_debug( __METHOD__ . "(): Empty input: {$field->id}.{$input_number}" );
			}
		}
	}
	GFCommon::log_debug( __METHOD__ . '(): Returning validation result.' );
	return $result;
}, 10, 4 );

Compare value against another field

This example validates field 2 to make sure the value does not match field 1.

// The add_filter line below targets field id 2 in a form that has id 10.
add_filter( 'gform_field_validation_10_2', function ( $result, $value, $form, $field ) {
    $master = rgpost( 'input_1' ); // Change 1 to the id of the other field.
    if ( $result['is_valid'] && $value == $master ) {
        $result['is_valid'] = false;
        $result['message']  = 'Please enter a different email.';
    }
 
    return $result;
}, 10, 4 );

Phone field validation

This example shows how you can use regex to validate the value of phone field.

add_filter( 'gform_field_validation', 'validate_phone', 10, 4 );
function validate_phone( $result, $value, $form, $field ) {
    $pattern = "/^(\+44\s?7\d{3}|\(?07\d{3}\)|\(?01\d{3}\)?)\s?\d{3}\s?\d{3}$/";
    if ( $field->type == 'phone' && $field->phoneFormat != 'standard' && ! preg_match( $pattern, $value ) && $value != '' ) {
        $result['is_valid'] = false;
        $result['message']  = 'Please enter a valid phone number';
    }
 
    return $result;
}

Time field validation

This example validates field 2 in form 1 to check that time is between two set times (12 hour time format).

add_filter( 'gform_field_validation_1_2', 'validate_time', 10, 4 );
function validate_time( $result, $value, $form, $field ) {
    //convert the entire time field array into a string, separating values with colons
    $input_time = implode( ':', $value );
    //replace colon between the time and am/pm with space and convert strings into a unix timestamp
    $time = strtotime( substr_replace( $input_time, ' ', -3, 1 ) );
    $max_time = strtotime( '17:00' );
    $min_time = strtotime( '09:00' );
 
    if ( $time < $min_time OR $time > $max_time ) {
        $result['is_valid'] = false;
        $result['message'] = 'Please select a time between 09:00 am and 05:00 pm';
    }
    return $result;
}

Check if email is on Mailchimp list

The following example shows how you return an error if the email is already on a Mailchimp list.

add_filter( 'gform_field_validation', function ( $result, $value, $form, $field ) {
	if ( ! class_exists( 'GF_MailChimp_API' ) || $field->get_input_type() !== 'email' || ! rgar( $result, 'is_valid' ) ) {
		return $result;
	}

	gf_mailchimp()->log_debug( 'gform_field_validation: running.' );
	$settings = gf_mailchimp()->get_plugin_settings();

	if ( empty( $settings['access_token'] ) || empty( $settings['server_prefix'] ) ) {
		gf_mailchimp()->log_debug( 'gform_field_validation: aborting; no access_token or server_prefix.' );

		return $result;
	}

	$entry   = GFFormsModel::get_current_lead();
	$feed    = gf_mailchimp()->get_single_submission_feed_by_form( $form, $entry );
	$list_id = rgars( $feed, 'meta/mailchimpList' );

	if ( empty( $list_id ) ) {
		gf_mailchimp()->log_debug( 'gform_field_validation: aborting; no list id.' );

		return $result;
	}

	try {

		// Get member info.
		$mc_api = new GF_MailChimp_API( $settings['access_token'], $settings['server_prefix'] );
		$member = $mc_api->get_list_member( $list_id, $value );

		// Set member status.
		$member_status = $member['status'];

	} catch ( Exception $e ) {

		// The email is not on the list or there was an API issue.
		$member_status = false;

	}

	gf_mailchimp()->log_debug( 'gform_field_validation: member status => ' . print_r( $member_status, 1 ) );

	if ( $member_status == 'subscribed' ) {
		$result['is_valid'] = false;
		$result['message']  = empty( $field->errorMessage ) ? 'This address is already on the list.' : $field->errorMessage;
	}

	return $result;
}, 10, 4 );

Date field validation

The following example shows how you override the default validation when using a custom date format.

add_filter( 'gform_field_validation', 'custom_date_validation', 10, 4 );
function custom_date_validation( $result, $value, $form, $field ) {
    if ( ! $result['is_valid'] && $field->get_input_type() == 'date' ) {
        $date = GFCommon::parse_date( $value );
 
        if ( ! GFCommon::is_empty_array( $date ) && checkdate( $date['month'], $date['day'], $date['year'] ) ) {
            $result['is_valid'] = true;
            $result['message']  = '';
        } else {
            $result['message'] = 'Please enter a valid date.';
        }
    }
 
    return $result;
}

Product field quantity validation

The following example shows how you perform custom validation of the product field quantity input. This example is validating that the quantity input of field 1 on form 10 contains a value less than 10.

add_filter( 'gform_field_validation_10_1', 'product_quantity_validation', 10, 4 );
function product_quantity_validation( $result, $value, $form, $field ) {
    $quantity = intval( rgar( $value, $field->id . '.3' ) );
 
    if ( $result['is_valid'] && $quantity > 10 ) {
        $result['is_valid'] = false;
        $result['message']  = 'Please enter a value less than 10';
    }
 
    return $result;
}

Email validation by third-party API

The following example shows how you can send the value of an Email type field to a third-party API to determine if the email is valid. In this example, we are using the QuickEmailVerification API.

add_filter( 'gform_field_validation', function ( $result, $value, $form, $field ) {
    if ( $field->get_input_type() === 'email' && $result['is_valid'] ) {
        $request_url = add_query_arg(
            array(
                'email'  => $value,
                'apikey' => 'your_api_key_here',
            ),
            'http://api.quickemailverification.com/v1/verify'
        );
 
        $response       = wp_remote_get( $request_url );
        $response_json  = wp_remote_retrieve_body( $response );
        $response_array = json_decode( $response_json, 1 );
 
        if ( rgar( $response_array, 'result' ) !== 'valid' ) {
            $result['is_valid'] = false;
            $result['message']  = 'Email is invalid';
        }
    }
 
    return $result;
}, 10, 4 );

Multiple emails in one field

The following example shows how you can override the default validation of a text field to validate multiple comma separated emails. Add multiple-emails to the Custom CSS Class setting on the Appearance panel of the field settings.

add_filter( 'gform_field_validation', function ( $result, $value, $form, $field ) {
	if ( ! $result['is_valid'] || $field->get_input_type() !== 'text' || strpos( $field->cssClass, 'multiple-emails' ) === false ) {
		return $result;
	}

	if ( ! GFCommon::is_valid_email_list( $value ) ) {
		$result['is_valid'] = false;
		$result['message']  = 'One or more email addresses entered are invalid, please check the formatting (e.g. [email protected],[email protected]).';
	}

	return $result;
}, 10, 4 );

Date field – Age Validation

The following example shows how you can override the default validation of the date field to validate the age. In this case, we are validating field #2 on form #10 and returning an error if the supplied date is less than 18 years ago.

add_filter( 'gform_field_validation_10_2', function ( $result, $value, $form, $field ) {
    if ( $result['is_valid'] ) {
        if ( is_array( $value ) ) {
            $value = array_values( $value );
        }
        $date_value = GFFormsModel::prepare_date( $field->dateFormat, $value );
 
        $today = new DateTime();
        $diff  = $today->diff( new DateTime( $date_value ) );
        $age   = $diff->y;
 
        if ( $age < 18 ) {
            $result['is_valid'] = false;
            $result['message']  = 'Underage';
        }
    }
 
    return $result;
}, 10, 4 );

Survey Rank field

The following example shows how you require the user to change the order of the choices in the rank type survey field.

add_filter( 'gform_field_validation', function( $result, $value, $form, $field ) {
    if ( $field->get_input_type() == 'rank' ) {
        $choice_values = array();
        foreach ( $field->choices as $choice ) {
            $choice_values[] = $choice['value'];
        }
 
        if ( $value == implode( ',', $choice_values ) ) {
            $result['is_valid'] = false;
            $result['message']  = 'Please rank the choices.';
        }
    }
 
    return $result;
}, 10, 4 );

Multi-file Upload Minimum Count

The following example shows how you require the user to upload a minimum number of files for the multi-file enabled upload field, in this case field 2 of form 50.

	add_filter( 'gform_field_validation_50_2', function( $result, $value, $form, $field ) {
		if ( $field->multipleFiles ) {
			$input_name = 'input_' . $field->id;
			$files      = isset( GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $form['id'] ][ $input_name ] : array();
			GFCommon::log_debug( __METHOD__ . '(): $files content => ' . print_r( $files, true ) );
			$count      = count( $files );
			$min        = 2;

			if ( $result['is_valid'] && $count < $min ) {
				$result['is_valid'] = false;
				$result['message']  = "Number of files is less than the minimum required ({$min}).";
			}
		}

		return $result;
	}, 10, 4 );

Current User Password validation

The following example shows you how to validate the current user password for a password field or a text field with password input enabled for form 20.

add_filter( 'gform_field_validation_20', 'check_current_password', 10, 4 );
function check_current_password( $result, $value, $form, $field ) {
    if ( $field->type === 'password' || ( $field->get_input_type() === 'text' && $field->enablePasswordInput ) ) {
        $user = wp_get_current_user();
 
        if ( empty( $value ) || ! wp_check_password( addslashes( $value ), $user->data->user_pass, $user->ID ) ) {
            $result['is_valid'] = false;
            $result['message']  = 'Invalid current password. Please try again.';
        }
    }
 
    return $result;
}

List field validation

The following example shows you how to require the user to fill all inputs of a list field, in this case field 1 of form 53.

// Require all inputs for a list field.
 
add_filter( 'gform_field_validation_53_1', 'validate_list_field', 10, 4 );
function validate_list_field( $result, $value, $form, $field ) {
    if ( $field->type == 'list' ) {
 
        GFCommon::log_debug( __METHOD__ . '(): List Field: ' . print_r( $value, true ) );
 
        foreach ( $value as $row_values ) {
        GFCommon::log_debug( __METHOD__ . '(): Row Value: ' . print_r( $row_values, true ) );
 
            $column_1 = rgar( $row_values, 'Type' );
            GFCommon::log_debug( __METHOD__ . '(): Column 1: ' . print_r( $column_1, true ) );
 
            $column_2 = rgar( $row_values, 'Cost' );
            GFCommon::log_debug( __METHOD__ . '(): Column 2: ' . print_r( $column_2, true ) );
 
            $column_3 = rgar( $row_values, 'Frequency' );
            GFCommon::log_debug( __METHOD__ . '(): Column 3: ' . print_r( $column_3, true ) );
 
            if ( empty( $column_1 ) || empty( $column_2 ) || empty( $column_3 ) ) {
                $has_empty_input = true;
            }
        }
 
        if ( $has_empty_input ) {
            $result['is_valid'] = false;
            $result['message']  = 'All inputs are required!';
        }
    }
 
    return $result;
}

Prevent submission based on a word list

The following example shows you how to prevent a submission if certain words are entered into any Single Line Text or Paragraph fields.

add_filter( 'gform_field_validation', function( $result, $value, $form, $field ) {
	GFCommon::log_debug( __METHOD__ . '(): Running...' );
	// Only for Single Line Text and Paragraph fields.
	if ( 'text' === $field->type || 'textarea' === $field->type ) {
		if ( $result['is_valid'] ) {
			$stop_words = array( // List of words to not allow in lowercase.
				'viagra',
				'porn',
				'sidenafil',
			);

			// Trim and lowercase the input.
			$lower_value = strtolower( trim( $value ) );
			
			// Split the input into words.
			$words = preg_split( '/\s+/', $lower_value );
			
			// Check if there's only one word and if it's in the stop words list.
			if ( 1 === count( $words ) && in_array( $words[0], $stop_words, true ) ) {
				GFCommon::log_debug( __METHOD__ . "(): Stop word detected as the only word in field id {$field->id}. Stop Word: {$words[0]}" );
				$result['is_valid'] = false;
				$result['message']  = 'Sorry, your submission contains a word that is not allowed.';
			} else {
				// Check if any stop word is part of the submitted text.
				foreach ( $stop_words as $stop_word ) {
					if ( false !== strpos( $lower_value, $stop_word ) ) {
						GFCommon::log_debug( __METHOD__ . "(): Stop word detected in field id {$field->id}. Stop Word: {$stop_word}" );
						$result['is_valid'] = false;
						$result['message']  = 'Sorry, your submission contains a word that is not allowed.';
						break;
					}
				}
			}
		}
	}

	return $result;
}, 10, 4 );

Prevent use of passwords exposed in data breaches

The following example shows how you can use the Pwned Passwords API from https://haveibeenpwned.com/ to check if the submitted password is vulnerable to credential stuffing attacks.

add_filter( 'gform_field_validation', 'check_pwnedpasswords', 60, 4 );
function check_pwnedpasswords( $result, $value, $form, $field ) {
	// Return early if there is no value, the value already failed validation, or it's the wrong field.
	if ( empty( $value ) || empty( $result['is_valid'] ) || ! ( $field->type === 'password' || ( $field->get_input_type() === 'text' && $field->enablePasswordInput ) ) ) {
		return $result;
	}

	// Hash the value.
	$hash = sha1( $value );

	// Get the first 5 characters of the hash.
	$prefix = substr( $hash, 0, 5 );

	// Send the hash prefix to the API.
	$response = wp_remote_get( 'https://api.pwnedpasswords.com/range/' . $prefix );

	// Return early if the request fails.
	if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
		return $result;
	}

	// Get the hash with the first 5 characters removed.
	$suffix = substr( $hash, 5 );

	// Return early if the hash suffix isn't found in the response body.
	if ( ! preg_match( "/{$suffix}:(\d+)/i", wp_remote_retrieve_body( $response ), $matches ) ) {
		return $result;
	}

	// Get the number of times the password has been found in breach data.
	$count = intval( $matches[1] );

	// Fail validation if the count is greater than zero.
	if ( $count > 0 ) {
		$result['is_valid'] = false;
		$result['message']  = sprintf( 'Please enter a different password. This password has been found in a data breach. Visit %sHave I Been Pwned (HIBP)%s for more details.', '<a href="https://haveibeenpwned.com/Passwords" target="_blank">', '</a>' );
		GFCommon::log_debug( __METHOD__ . sprintf( '(): Password found in haveibeenpwned.com breach data for field #%d(%s - %s).', $field->id, $field->label, $field->type ) );
	}

	return $result;
}

Prevent submission if a URL is entered into Text or Paragraph fields

The following example shows you how to prevent a submission if a URL is entered into any Single Line Text or Paragraph fields.

	add_filter( 'gform_field_validation', function ( $result, $value, $form, $field ) {
		// Only for Single Line Text or Paragraph fields.
		if ( $field->type == 'text' || $field->type == 'textarea' ) {

			$has_url = false;

			// The following regex is just an example, feel free to change it.
			if ( preg_match ( '/www\.|http:|https:\/\/[a-z0-9_]+([\-\.]{1}[a-z_0-9]+)*\.[_a-z]{2,5}'.'((:[0-9]{1,5})?\/.*)?$/i', $value ) ) {
				$has_url = true;
			}

			if ( true === $has_url ) {
				$result['is_valid'] = false;
				$result['message']  = empty( $field->errorMessage ) ? 'Sorry, URL not allowed!' : $field->errorMessage;
			}
		}

		return $result;
	}, 10, 4 );

Prevent submission of Cyrillic characters

The following example shows you how to prevent a submission if Cyrillic characters are entered into any Single Line Text or Paragraph fields. If you want to apply this validation to any field type, just remove the if statement at the start of the snippet.

add_filter( 'gform_field_validation', 'gf_cyrillic_validation', 10, 4 );
function gf_cyrillic_validation( $result, $value, $form, $field ) {
    GFCommon::log_debug( __METHOD__ . '(): running for field type ' . $field->type );
    if ( 'text' !== $field->type && 'textarea' !== $field->type ) {
        GFCommon::log_debug( __METHOD__ . '(): No text or paragraph field.' );
        return $result;
    }
 
    // Cyrillic check.
    $cyrillic = preg_match( '/[\p{Cyrillic}]/u', $value);
 
    if ( $result['is_valid'] && $cyrillic ) {
        GFCommon::log_debug( __METHOD__ . '(): Cyrillic detected!' );
        $result['is_valid'] = false;
        $result['message'] = 'Data entered not allowed.';
    }
    return $result;
}

Validate uploaded files

The following example shows how you can perform custom validation of uploaded files. This approach works with both the single and multi-file enabled field with Gravity Forms 2.8.6 and newer.

add_filter( 'gform_field_validation', function ( $result, $value, $form, $field ) {
	if ( ! rgar( $result, 'is_valid' ) || $field->get_input_type() !== 'fileupload' ) {
		return $result;
	}

	$draft_entry_value = rgar( GFFormsModel::get_current_lead( $form ), $field->id );

	$files = empty( $draft_entry_value ) ? null : json_decode( $draft_entry_value, true );
	if ( empty( $files ) ) {
		return $result;
	}

	foreach ( $files as $file ) {
		$tmp_path = rgar( $file, 'tmp_path' );
		if ( ! empty( $tmp_path ) && ! file_exists( $tmp_path ) ) {
			// The file hasn't been moved to the form-specific tmp folder yet, using the original in the PHP tmp folder instead.
			$tmp_path = rgars( $_FILES, sprintf( 'input_%d/tmp_name', $field->id ) );
		}

		$tmp_url       = rgar( $file, 'tmp_url' );
		$tmp_name      = rgar( $file, 'tmp_name' );
		$uploaded_name = rgar( $file, 'uploaded_name' );

		// Perform your custom file check here, setting $is_valid to true or false.
		$is_valid = true;

		if ( ! $is_valid ) {
			$result['is_valid'] = false;
			$result['message']  = sprintf( '%s is not a valid file.', $uploaded_name );

			return $result;
		}
	}

	return $result;
}, 10, 4 );

Placement

This code can be used in the functions.php file of the active theme, a custom functions plugin, a custom add-on, or with a code snippets plugin.

See also the PHP section in this article: Where Do I Put This Code?

Source Code

As of Gravity Forms 2.7 this filter is located in GFFormDisplay::validate_field() in form_display.php. It was previously located in GFFormDisplay::validate().