The Smart Form is the ready-made login and registration form included with Customer Email Verification Pro. It can replace the WooCommerce My Account form, or be placed on any page with the [cev_smart_form] shortcode.
By default the registration step collects an email address and a password, plus a phone number when phone registration is enabled. This page documents the filters and actions available to extend it.
All snippets on this page belong in your child theme’s functions.php file, in a custom plugin, or in a code-snippets plugin.
How the Smart Form Creates an Account
Understanding the order of operations is useful before extending the form. Registration happens in two steps:
- The customer submits the form. The plugin validates the submitted values, holds them temporarily, and sends the one-time code. No account is created at this point.
- The customer enters the code. Once it is confirmed, the WooCommerce customer account is created and the held values are saved to it.
This ordering means an abandoned verification never leaves a half-created account behind. It also means WooCommerce’s own registration hooks, which run when the account is created, fire during step 2 rather than step 1.
Adding Custom Registration Fields
Use the cev_smart_form_custom_fields filter to add fields to the registration step. Requires version 3.0.2 or later.
The array key you use is the WordPress user-meta key the value is saved to. Because first_name, last_name and the billing_* fields are all user-meta keys, naming the field correctly is all that is required for the value to be stored where WooCommerce expects it.
add_filter( 'cev_smart_form_custom_fields', function ( $fields ) {
$fields['first_name'] = array(
'label' => 'First name',
'type' => 'text',
'required' => true,
'placement' => 'after_email',
'priority' => 10,
);
$fields['last_name'] = array(
'label' => 'Last name',
'type' => 'text',
'required' => true,
'placement' => 'after_email',
'priority' => 20,
);
return $fields;
} );
A field with options renders as a choice control. The array key is the value saved, and the array value is the label shown:
$fields['billing_country'] = array(
'label' => 'Country',
'type' => 'select',
'required' => true,
'placement' => 'before_submit',
'options' => array(
'US' => 'United States',
'GB' => 'United Kingdom',
'IN' => 'India',
),
);
$fields['terms_accepted'] = array(
'label' => 'I agree to the <a href="/terms/">terms and conditions</a>',
'type' => 'acceptance',
'required' => true,
'placement' => 'before_submit',
);
Values are validated as the customer fills in the form, held until the one-time code is confirmed, and written to the account only after verification succeeds.
Field Arguments
| Argument | Description |
|---|---|
| Array key | The field key, and also the user-meta key the value is saved to. For example first_name, last_name, billing_company. |
| label | The field label shown on the form. May contain a single link, which is useful for a terms and conditions checkbox. |
| type | Input type. Defaults to text. See the list of supported types below. |
| required | Set to true to make the field mandatory. Defaults to false. |
| placement | Where the field appears in the form. Defaults to before_submit. See the list of positions below. |
| priority | Sort order within the chosen position. Lower numbers appear first. Defaults to 10. |
| placeholder | Optional placeholder text. |
| options | Required for select, radio and checkbox_group. Accepts a simple list, or an array of value to label pairs where the array key is the value saved. |
Supported Field Types
text, email, tel, url, number, date, textarea, select, radio, checkbox_group and acceptance (a single checkbox, intended for terms and conditions).
Field Positions
register_top, after_email, after_phone, after_password and before_submit.
Reserved Keys
These keys are used by the form’s own inputs and cannot be used for a custom field: email, password, phone, login, otp, nonce, action, channel and remember.
Acting on Saved Values
To store a value somewhere other than user meta, use the cev_smart_form_custom_fields_saved action. It runs once the account has been created and verified.
add_action( 'cev_smart_form_custom_fields_saved', function ( $user_id, $values ) {
// $values is keyed by field key, already validated and sanitized.
}, 10, 2 );
Stores With Extra Required WooCommerce Registration Fields
Many stores add required fields to the standard WooCommerce registration form, such as First Name or a company name, using a plugin, a theme template override or a custom snippet. Those rules are enforced through WooCommerce’s registration validation hooks, woocommerce_register_post and woocommerce_registration_errors.
As described above, those hooks run when the account is created, which is after the one-time code is confirmed. If a required field is not part of the Smart Form, that validation has nothing to check against and registration will not complete.
Note that the Smart Form does fire the standard woocommerce_register_form hook, so fields added by a plugin through that hook already render inside it. The two approaches below apply when the fields come from somewhere else, such as a template override or a validation-only snippet.
Option 1: Collect the Field and Pass It Through
Add the field to the Smart Form, then make its value available to the existing validation, which reads from $_POST. This keeps the store’s validation rules intact.
// 1) Add the fields to the Smart Form registration step.
add_filter( 'cev_smart_form_custom_fields', function ( $fields ) {
$fields['first_name'] = array(
'label' => 'First name',
'type' => 'text',
'required' => true,
'placement' => 'after_email',
'priority' => 10,
);
$fields['last_name'] = array(
'label' => 'Last name',
'type' => 'text',
'required' => true,
'placement' => 'after_email',
'priority' => 20,
);
return $fields;
} );
// 2) Make those values available to the existing registration validation.
add_action( 'woocommerce_register_post', function ( $username, $email, $errors ) {
$pending = get_transient( 'cev_sf_reg_' . md5( strtolower( $email ) ) );
if ( ! is_array( $pending ) || empty( $pending['custom'] ) ) {
return;
}
// Map Smart Form field keys to the $_POST names the validation expects.
$map = array(
'first_name' => array( 'first_name', 'billing_first_name' ),
'last_name' => array( 'last_name', 'billing_last_name' ),
);
foreach ( $pending['custom'] as $key => $value ) {
$targets = isset( $map[ $key ] ) ? $map[ $key ] : array( $key );
foreach ( $targets as $target ) {
if ( empty( $_POST[ $target ] ) ) {
$_POST[ $target ] = $value;
}
}
}
}, 1, 3 );
Add further fields the same way: repeat the $fields[...] block using the field’s meta key, and add a line to $map if the validation reads it under a different $_POST name.
Option 2: Limit the Existing Validation to the WooCommerce Form
If the extra fields are not needed for Smart Form registrations, the existing validation can be limited to the standard WooCommerce form. The Smart Form still enforces its own required fields, and WooCommerce’s core email and username checks remain in force.
add_filter( 'woocommerce_registration_errors', function ( $errors, $username, $email ) {
$action = isset( $_POST['action'] ) ? sanitize_key( wp_unslash( $_POST['action'] ) ) : '';
if ( 'cev_smart_verify_register' !== $action && 'cev_smart_register' !== $action ) {
return $errors;
}
$keep = array(
'registration-error-email-exists',
'registration-error-invalid-email',
'registration-error-missing-email',
'registration-error-username-exists',
'registration-error-invalid-username',
);
$clean = new WP_Error();
foreach ( $errors->get_error_codes() as $code ) {
if ( in_array( $code, $keep, true ) ) {
foreach ( $errors->get_error_messages( $code ) as $msg ) {
$clean->add( $code, $msg );
}
}
}
return $clean;
}, 99, 3 );
Changing the Redirect After Login or Registration
By default the Smart Form sends customers to the My Account page after they sign in or complete registration. Use the cev_smart_form_register_redirect filter to change that. The same filter covers all three paths: password login, email one-time-code login, and registration.
add_filter( 'cev_smart_form_register_redirect', function ( $url, $user_id ) {
return wc_get_page_permalink( 'shop' );
}, 10, 2 );
| Parameter | Description |
|---|---|
| $url | The default redirect URL, normally the My Account page. |
| $user_id | The ID of the customer who just signed in or registered. |
Returning to the Page the Customer Originally Requested
On a private or members-only store, visitors are typically sent to the login page with a redirect_to parameter recording where they were headed. This version reads that parameter and returns them there, falling back to the Shop page.
add_filter( 'cev_smart_form_register_redirect', function ( $url, $user_id ) {
$referer = wp_get_referer(); // The page the Smart Form was submitted from.
if ( $referer ) {
$query = wp_parse_url( $referer, PHP_URL_QUERY );
if ( $query ) {
parse_str( $query, $args );
if ( ! empty( $args['redirect_to'] ) ) {
return wp_validate_redirect( urldecode( $args['redirect_to'] ), $url );
}
}
}
return wc_get_page_permalink( 'shop' );
}, 10, 2 );
Checking Verification Status in Your Own Code
Use is_user_email_verified() to check whether a customer has verified their email address. It returns true for a fully verified customer and for one awaiting their first paid order when Paid-Order Gatekeeping is enabled, so it is the correct check for any access or prompt decision.
if ( function_exists( 'cev_pro' ) && cev_pro()->function->is_user_email_verified( $user_id ) ) {
// The customer has verified their email address.
}
Customers who register through the Smart Form are verified by definition, since the account is only created once the code is confirmed. This check is most useful for accounts created another way, such as by an administrator, an import or a migration.
The example below blocks unverified customers from the shop and product pages and sends them to My Account. Store staff are never affected.
add_action( 'template_redirect', function () {
if ( is_admin() || ! is_user_logged_in() || ! function_exists( 'cev_pro' ) ) {
return;
}
if ( ! ( is_shop() || is_product() || is_product_category() || is_product_tag() ) ) {
return;
}
$user_id = get_current_user_id();
if ( user_can( $user_id, 'edit_posts' ) ) {
return; // Never lock out store staff.
}
if ( cev_pro()->function->is_user_email_verified( $user_id ) ) {
return;
}
wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) );
exit;
}, 5 );
In most cases a snippet is not needed. The setting Settings > Login Authentication > Require unverified logged-in customers to verify automatically sends a code and shows the verification popup to any unverified customer on their next page load.
Smart Form Filter Reference
| Filter | Description |
|---|---|
| cev_smart_form_custom_fields | Add custom fields to the registration step. |
| cev_smart_form_custom_fields_saved | Action fired after custom field values are saved to a new account. |
| cev_smart_form_register_redirect | Change where customers are sent after login or registration. |
| cev_smart_form_auto_login | Return false to stop signing the customer in automatically after registration. |
| cev_smart_form_password_is_strong | Override the password strength rule applied to new registrations. |
| cev_smart_form_fire_wc_hooks | Return false to stop the Smart Form firing the standard WooCommerce login and registration form hooks, which are used by captcha and security plugins. |