Validation Hooks Reference (PHP)
Form Plant's server-side validation can be customized freely through WordPress filter hooks. From replacing error messages to per-field custom checks and external API integration, everything can be implemented simply by adding a PHP filter.
Use JavaScript customization for instant in-browser feedback ( better UX ), and the PHP hooks on this page for reliable validation ( security ). Client-side checks can easily be bypassed with tools such as DevTools, so input validation must always be performed on the server side as well.
This page covers validation-specific hooks only. For hooks related to email delivery, post-submission actions, redirects, file uploads, dynamic choice generation, form settings, and so on, see the PHP Hook Reference.
Hook List
fplant_before_validation
Processes data before validation begins. Useful for normalizing phone numbers, converting full-width to half-width characters, and similar tasks.
| Parameter | Type | Description |
|---|---|---|
$data | array | Submitted data |
$fields | array | Field settings |
$form_id | int | Form ID |
Return value: array — the processed submitted data
fplant_validation_required_message
Customizes the error message for required fields.
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$value | mixed | Input value |
$data | array | The entire submitted data |
Return value: string — the customized error message
fplant_validate_field_{$field_name}
Completely overrides validation for a specific field. The field name ( e.g. email ) is embedded in the hook name.
| Parameter | Type | Description |
|---|---|---|
$error | null | Initial value |
$field | array | Field settings |
$value | mixed | Input value |
$data | array | The entire submitted data |
$form_id | int | Form ID |
Return value:
null— run the standard validationfalse— no error ( skip the standard validation )string— error message ( skip the standard validation )
Returning anything other than null skips the standard validation. If you also want the standard checks to run, return null.
This hook only fires for fields that have a value ( file fields excepted ) . Fields with an empty value ( more precisely, any empty value other than '0' ) are skipped before this hook, so fplant_validate_field_{name} is not called ( empty fields are left to the standard required check by design ) . It therefore cannot be used for validation conditioned on emptiness ( e.g. making a field required based on another field's value ) . For that, use fplant_validation_errors, which fires for the whole form.
fplant_validation_message_email
Customizes the error message for email address fields.
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$value | string | Input value |
$context | array | Context information ( type: 'format' ) |
Return value: string
fplant_validation_message_url
Customizes the error message for URL fields. The parameters are the same as fplant_validation_message_email.
fplant_validation_message_tel
Customizes the error message for phone number fields. The parameters are the same as fplant_validation_message_email.
fplant_validation_message_number
Customizes the error message for number fields.
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$value | string | Input value |
$context | array | type: 'format' / 'min' / 'max', min, max |
Return value: string
fplant_validation_message_password
Customizes the error message for password fields.
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$value | string | Input value |
$context | array | type: 'min_length' / 'strength' |
Return value: string
fplant_validation_message_postal_code
Customizes the error message for postal code fields. It also fires for the postal code subfield inside an address ( address ) field.
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$value | string | Input value |
$context | array | Context information ( type: 'format' ) |
Return value: string
fplant_validation_message_name_kana
Customizes the kana-validation error message for the name ( furigana ) field. This is the only hook that does not have a fourth argument ( $context ).
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$value | string | Input value |
Return value: string
fplant_validate_field_type_{$field_type}
Additional validation per field type ( email, tel, number, etc. ). It runs after the standard validation.
| Parameter | Type | Description |
|---|---|---|
$error | false / string | Result of the standard validation |
$field | array | Field settings |
$value | mixed | Input value |
Return value: false ( no error ) or string ( error message )
fplant_validation_message_min_length
Customizes the minimum character count error message.
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$value | string | Input value |
$validation | array | Validation settings |
Return value: string
fplant_validation_message_max_length
Customizes the maximum character count error message. The parameters are the same as fplant_validation_message_min_length.
fplant_validation_message_pattern
Customizes the regular expression pattern error message. The parameters are the same as fplant_validation_message_min_length.
fplant_validate_custom_rules
Adds custom validation rules. By defining your own key in the field's validation array and writing the check logic in this hook, you can implement new rules.
| Parameter | Type | Description |
|---|---|---|
$error | false / string | Result of the existing error checks |
$field | array | Field settings |
$value | string | Input value |
$validation | array | Validation settings |
Return value: false ( no error ) or string ( error message )
fplant_validation_message_file
Customizes the file upload error message.
| Parameter | Type | Description |
|---|---|---|
$message | string | Default error message |
$field | array | Field settings |
$file | array | The $_FILES array |
$context | array | type: 'upload_error' / 'size' / 'extension', max_size, allowed_types |
Return value: string
fplant_validation_errors
A hook for making a final adjustment to the entire error array after every field has been validated.
| Parameter | Type | Description |
|---|---|---|
$errors | array | Error array |
$fields | array | Field settings |
$data | array | Submitted data |
Return value: array
Hook Execution Order
When
fplant_validate_field_{name}returns anything other thannull, the standard validation ( everything below "Standard validation" in the diagram above ) is skipped.
Examples
Example 1: Localizing the Required Error Message
add_filter( 'fplant_validation_required_message', function( $message, $field ) {
if ( get_locale() === 'en_US' ) {
return sprintf( '%s is required', $field['label'] );
}
return $message;
}, 10, 2 );
Example 2: Restricting Validation to Company Email Domains
add_filter( 'fplant_validate_field_company_email', function( $error, $field, $value, $data, $form_id ) {
$allowed_domains = array( 'example.com', 'company.co.jp' );
if ( ! empty( $value ) && is_email( $value ) ) {
$domain = substr( strrchr( $value, '@' ), 1 );
if ( ! in_array( $domain, $allowed_domains, true ) ) {
return 'Please enter a company email address (@example.com or @company.co.jp).';
}
}
// Returning null also runs the standard validation.
return $error;
}, 10, 5 );
Example 3: Adding a Rule That Forbids Toll-Free Numbers for the Tel Type
add_filter( 'fplant_validate_field_type_tel', function( $error, $field, $value ) {
// If there is already an error, return it.
if ( $error !== false ) {
return $error;
}
$cleaned_tel = preg_replace( '/[^0-9]/', '', $value );
if ( strpos( $cleaned_tel, '0120' ) === 0 || strpos( $cleaned_tel, '0800' ) === 0 ) {
return sprintf( 'Toll-free numbers cannot be used for %s.', $field['label'] );
}
return false;
}, 10, 3 );
Example 4: Adding a Custom "Age Restriction" Rule
add_filter( 'fplant_validate_custom_rules', function( $error, $field, $value, $validation ) {
if ( isset( $validation['age_restriction'] ) && ! empty( $value ) ) {
$min_age = intval( $validation['age_restriction'] );
$input_age = intval( $value );
if ( $input_age < $min_age ) {
return isset( $validation['age_restriction_message'] )
? $validation['age_restriction_message']
: sprintf( 'Only people aged %s or older may apply.', $min_age );
}
}
return $error;
}, 10, 4 );
Example 5: Verifying a Postal Code Against an External API ( cached with Transients )
add_filter( 'fplant_validate_field_postal_code', function( $error, $field, $value, $data, $form_id ) {
// This hook does not fire for empty values, so this guard is effectively unreachable ( defensive )
if ( empty( $value ) ) {
return $error;
}
$cache_key = 'postal_code_' . md5( $value );
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached === 'valid' ? false : $cached;
}
$response = wp_remote_get(
'https://api.zipaddress.net/?zipcode=' . urlencode( $value ),
array( 'timeout' => 5 )
);
if ( is_wp_error( $response ) ) {
return 'Failed to verify the postal code. Please try again later.';
}
$body = wp_remote_retrieve_body( $response );
$result = json_decode( $body, true );
if ( empty( $result['data'] ) ) {
$message = 'Please enter a valid postal code.';
set_transient( $cache_key, $message, HOUR_IN_SECONDS );
return $message;
}
set_transient( $cache_key, 'valid', HOUR_IN_SECONDS );
return false;
}, 10, 5 );
Example 6: Normalizing Submitted Data ( removing hyphens, full-width to half-width )
add_filter( 'fplant_before_validation', function( $data, $fields, $form_id ) {
foreach ( $fields as $field ) {
if ( ! isset( $data[ $field['name'] ] ) ) {
continue;
}
// Remove hyphens and similar characters from phone numbers.
if ( $field['type'] === 'tel' ) {
$data[ $field['name'] ] = preg_replace( '/[^0-9]/', '', $data[ $field['name'] ] );
}
// Convert full-width to half-width for number fields.
if ( $field['type'] === 'number' ) {
$data[ $field['name'] ] = mb_convert_kana( $data[ $field['name'] ], 'n' );
}
}
return $data;
}, 10, 3 );
Example 7: Customizing the File Size Error Message
add_filter( 'fplant_validation_message_file', function( $message, $field, $file, $context ) {
if ( $context['type'] === 'size' ) {
return sprintf(
'The file for %s is too large. Please choose a file of %sMB or less (current: %sMB).',
$field['label'],
$context['max_size'],
round( $file['size'] / 1024 / 1024, 2 )
);
}
return $message;
}, 10, 4 );
Best Practices
How to Return Errors
// ✅ Return a string when there is an error.
return 'Error message';
// ✅ Return false when there is no error.
return false;
// ❌ Do not return null or true (except for fplant_validate_field_{$field_name}).
Performance Considerations
Validators that call external APIs should always cache results with the Transient API or similar. Hitting the API on every form submission can cause display delays and trigger API rate limits.
Security Considerations
- Always sanitize input values with
sanitize_text_field()or similar. - Set a
timeouton external API requests. - When including input values in error messages, escape them with
esc_html().
Summary
By using PHP filter hooks, all of the following customizations are handled entirely on the server side.
- Localizing and rewording error messages
- Extending validation per field type
- Adding custom validation to specific fields
- External API integration validation
- Adding custom validation rules
- Normalizing data before validation