I’m just wondering why wordpress doesn’t send confirmation mail every time user change his/her email address.
How do we know that email address is not fake or mistyped?
So can anyone give me some snippet to implement this function?
Update:
Here is the idea.
- user changes his/her mail
- We send confirmation email.
- If the user confirm that email in X days by clicking confirmation link, then the email should be changed. Else we should use existing email.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Like SickHippie posted this functionality is native to WordPress but only for a multisite setup so here is the two functions you need to get this to work on a single site setup which are mostly code one for one from the core /wp-admin/user-edit.php file
function custom_send_confirmation_on_profile_email() {
global $errors, $wpdb;
$current_user = wp_get_current_user();
if ( ! is_object($errors) )
$errors = new WP_Error();
if ( $current_user->ID != $_POST['user_id'] )
return false;
if ( $current_user->user_email != $_POST['email'] ) {
if ( !is_email( $_POST['email'] ) ) {
$errors->add( 'user_email', __( "<strong>ERROR</strong>: The e-mail address isn't correct." ), array( 'form-field' => 'email' ) );
return;
}
if ( email_exists( $_POST['email'] ) ) {
$errors->add( 'user_email', __( "<strong>ERROR</strong>: The e-mail address is already used." ), array( 'form-field' => 'email' ) );
delete_user_meta( $current_user->ID . '_new_email' );
return;
}
$hash = md5( $_POST['email'] . time() . mt_rand() );
$new_user_email = array(
'hash' => $hash,
'newemail' => $_POST['email']
);
update_user_meta( $current_user->ID . '_new_email', $new_user_email );
$content = apply_filters( 'new_user_email_content', __( "Dear user,
You recently requested to have the email address on your account changed.
If this is correct, please click on the following link to change it:
###ADMIN_URL###
You can safely ignore and delete this email if you do not want to
take this action.
This email has been sent to ###EMAIL###
Regards,
All at ###SITENAME###
###SITEURL###" ), $new_user_email );
$content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail='.$hash ) ), $content );
$content = str_replace( '###EMAIL###', $_POST['email'], $content);
$content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
$content = str_replace( '###SITEURL###', home_url(), $content );
wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), get_option( 'blogname' ) ), $content );
$_POST['email'] = $current_user->user_email;
}
}
add_action( 'personal_options_update', 'custom_send_confirmation_on_profile_email' );
// Execute confirmed email change. See send_confirmation_on_profile_email().
function verify_email_change(){
global $errors, $wpdb;
$current_user = wp_get_current_user();
if (in_array($GLOBALS['pagenow'], array('profile.php')) && $current_user->ID > 0) {
if (isset( $_GET[ 'newuseremail' ] ) && $current_user->ID ) {
$new_email = get_user_meta( $current_user->ID . '_new_email' );
if ( $new_email[ 'hash' ] == $_GET[ 'newuseremail' ] ) {
$user->ID = $current_user->ID;
$user->user_email = esc_html( trim( $new_email[ 'newemail' ] ) );
if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->users} WHERE user_login = %s", $current_user->user_login ) ) )
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_email = %s WHERE user_login = %s", $user->user_email, $current_user->user_login ) );
wp_update_user( get_object_vars( $user ) );
delete_user_meta( $current_user->ID . '_new_email' );
wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
die();
}
} elseif ( !empty( $_GET['dismiss'] ) && $current_user->ID . '_new_email' == $_GET['dismiss'] ) {
delete_user_meta( $current_user->ID . '_new_email' );
wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
die();
}
}
}
add_action('plugins_loaded','verify_email_change');
Method 2
This is a strange ‘feature’. The function is actually available inside WordPress (WordPress.com has it enabled for their managed blog service), but it is restricted to multisite. If you look in /wp-admin/includes/ms.php you’ll find the function that handles this – line 239 send_confirmation_on_profile_email().
Presumably, you could move this function into your functions.php or into a plugin to gain this functionality, possibly with a bit of tweaking to get it to work right. It doesn’t answer the “why”, but neither does the trac ticket on this subject here.
ETA: Looking further into it, there’s a few other functions you may need to duplicate as well – new_user_email_admin_notice() and update_option_new_admin_email() jump out as potentially necessary.
Method 3
Giri’s response didn’t work for me. I had to tweak mine to make it work (WordPress 3.5)
function cleanup_verify_email_change()
{
global $errors, $wpdb;
$current_user = wp_get_current_user();
// don't execute this if they're trying to dismiss a pending email change
if (in_array($GLOBALS['pagenow'], array('profile.php')) && $current_user->ID > 0 & !isset($_GET["dismiss"]))
{
if (isset( $_POST[ 'email' ] ) && ($current_user->user_email != $_POST['email']) )
{
$user->ID = $current_user->ID;
$user->user_email = esc_html( trim( $_POST[ 'email' ] ) );
if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->users} WHERE user_login = %s", $current_user->user_login ) ) ) {
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_email = %s WHERE user_login = %s", $user->user_email, $current_user->user_login ) );
}
wp_update_user( get_object_vars( $user ) );
wp_redirect( add_query_arg( array('updated' => 'true', 'multisite_cleanup' => 'true'), self_admin_url( 'profile.php' ) ) );
die();
}
elseif ( !empty( $_GET['dismiss'] ) && $current_user->ID . '_new_email' == $_GET['dismiss'] )
{
delete_user_meta( $current_user->ID . '_new_email' );
wp_redirect( add_query_arg( array('updated' => 'true', 'multisite_cleanup' => 'true'), self_admin_url( 'profile.php' ) ) );
die();
}
}
}
add_action('plugins_loaded','cleanup_verify_email_change');
Method 4
I’ve tweaked Giri code so that it works on my wordpress (version 4.8.1+)
before:
update_user_meta( $current_user->ID . '_new_email', $new_user_email );
after:
update_user_meta( $current_user->ID, '_new_email', $new_user_email );
The comma needs to replace the period.
Also:
$new_email['hash']; $new_email['newemail'];
became
$new_email[0]['hash']; $new_email[0]['newemail'];
Therefore:
function custom_send_confirmation_on_profile_email() {
global $errors, $wpdb;
$current_user = wp_get_current_user();
if ( ! is_object($errors) )
$errors = new WP_Error();
if ( $current_user->ID != $_POST['user_id'] )
return false;
if ( $current_user->user_email != $_POST['email'] ) {
if ( !is_email( $_POST['email'] ) ) {
$errors->add( 'user_email', __( "<strong>ERROR</strong>: The e-mail address isn't correct." ), array( 'form-field' => 'email' ) );
return;
}
if ( email_exists( $_POST['email'] ) ) {
$errors->add( 'user_email', __( "<strong>ERROR</strong>: The e-mail address is already used." ), array( 'form-field' => 'email' ) );
delete_user_meta( $current_user->ID, '_new_email' );
return;
}
$hash = md5( $_POST['email'] . time() . mt_rand() );
$new_user_email = array(
'hash' => $hash,
'newemail' => $_POST['email']
);
update_user_meta( $current_user->ID, '_new_email', $new_user_email );
$content = apply_filters( 'new_user_email_content', __( "Dear user,
You recently requested to have the email address on your account changed.
If this is correct, please click on the following link to change it:
###ADMIN_URL###
You can safely ignore and delete this email if you do not want to
take this action.
This email has been sent to ###EMAIL###
Regards,
All at ###SITENAME###
###SITEURL###" ), $new_user_email );
$content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail='.$hash ) ), $content );
$content = str_replace( '###EMAIL###', $_POST['email'], $content);
$content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
$content = str_replace( '###SITEURL###', home_url(), $content );
wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), get_option( 'blogname' ) ), $content );
$_POST['email'] = $current_user->user_email;
}
}
add_action( 'personal_options_update', 'custom_send_confirmation_on_profile_email' );
// Execute confirmed email change. See send_confirmation_on_profile_email().
function verify_email_change(){
global $errors, $wpdb;
$current_user = wp_get_current_user();
if (in_array($GLOBALS['pagenow'], array('profile.php')) && $current_user->ID > 0) {
if (isset( $_GET[ 'newuseremail' ] ) && $current_user->ID ) {
$new_email = get_user_meta( $current_user->ID, '_new_email' );
if ( $new_email[0]['hash'] == $_GET[ 'newuseremail' ] ) {
$user->ID = $current_user->ID;
$user->user_email = esc_html( trim( $new_email[0][ 'newemail' ] ) );
if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->users} WHERE user_login = %s", $current_user->user_login ) ) )
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_email = %s WHERE user_login = %s", $user->user_email, $current_user->user_login ) );
wp_update_user( get_object_vars( $user ) );
delete_user_meta( $current_user->ID, '_new_email' );
wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
die();
}
} elseif ( !empty( $_GET['dismiss'] ) && $current_user->ID . '_new_email' == $_GET['dismiss'] ) {
delete_user_meta( $current_user->ID, '_new_email' );
wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
die();
}
}
}
add_action('after_setup_theme','verify_email_change');
Cheers.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0