You need to put together some php & db calls to handle the form submission, generate some unique code for each email and sending the verification code.
Below I added a very basic example that can achieve that. It’s not a production ready code but tested and it works just fine.
Firstly, you need to add form tag with post method, so you can get the data in php.
<?php
global $verification_status;
?>
<div class="container" style="padding: 10px;">
<form action="<?php the_permalink(); ?>" method="post">
<?php wp_nonce_field( 'verify-email' ); ?>
<input class="email-input" name="email" type="email">
<?php if ( -1 === $verification_status ) { ?>
<input class="code-input" name="code" type="text" maxlength="6" required>
<?php } ?>
<button class="submit-btn"><?php echo -1 === $verification_status ? 'Send Code': 'Submit'; ?></button>
<?php if ( null !== $verification_status ) { ?>
<div class="msg-container">
<?php if ( true === $verification_status ) { ?>
<p class="code-yes">Success!</p>
<?php } elseif ( false === $verification_status ) { ?>
<p class="code-no">Wrong code!</p>
<?php } else if ( 0 === $verification_status ) { ?>
<p class="code-sent">Code sent, please check your email.</p>
<?php } else if ( 1 === $verification_status ) { ?>
<p class="code-sent">Already verified!</p>
<?php } ?>
</div>
<?php } ?>
</form>
</div>
<?php
You can add this to a page-template or shortcode.
Then to handle the form submission add a form handler with the init
or wp_loaded
hook.
add_action( 'init', 'wpse_416542_handle_form_submission' );
function wpse_416542_handle_form_submission() {
global $verification_status;
$nonce = ! empty( $_POST['_wpnonce'] ) ? sanitize_text_field( $_POST['_wpnonce'] ) : '';
$email = ! empty( $_POST['email'] ) ? sanitize_email( $_POST['email'] ) : '';
$code = ! empty( $_POST['code'] ) ? sanitize_text_field( $_POST['code'] ) : '';
if ( ! $code && $email && wp_verify_nonce( $nonce, 'verify-email' ) ) {
$email_list = get_option( 'email_verification_list', [] );
if ( isset( $email_list[ $email ] ) && true === $email_list[ $email ] ) {
$verification_status = true;
// do other staff.
return;
}
$rand_code = wp_rand( 100000, 999999 );
if ( ! empty( $email_list ) ) {
// lets make it unique
do {
$rand_code = wp_rand( 100000, 999999 );
} while ( in_array( $rand_code, array_values( $email_list ) ) );
}
$email_list[ $email ] = $rand_code;
update_option( 'email_verification_list', $email_list );
$message="Hi," . PHP_EOL . PHP_EOL;
$message .= 'Your verification code is: ' . $rand_code;
wp_mail( $email, 'Email Verification', $message );
$verification_status = -1;
return;
}
if ( $code && $email && wp_verify_nonce( $nonce, 'verify-email' ) ) {
$email_list = get_option( 'email_verification_list', [] );
if ( isset( $email_list[ $email ] ) ) {
if ( (int) $code === (int) $email_list[ $email ] ) {
$email_list[ $email ] = true; // Mark as verified.
$verification_status = true;
update_option( 'email_verification_list', $email_list );
} else {
$verification_status = false;
}
}
}
}
In the above form handler, if only email is submitted then
- Check if the email is already verified.
- If not then generate a
OTP
and sent it to the requested email address.
If both email and code is submitted
- Check if email is already verified
- If not Check the verification code submitted with stored code.
This example uses option table storing unencrypted verification codes. which is not very secure and also not very performant.
For production site you should use separate table to store the verification code. Also hash the code for security.
It is possible to use the password hasher but it recommend to use a TOTP
library that can generate the OTP
hash it and very the submitted code with the hash, and can automatically expire the OTP
after a defined time period.