5

I would like to implement a plugin that requires new users to reply to an email, to verify their email address, on registration. I am already doing extensive codex research, but I am very new and would appreciate some hints, especially regarding keeping the user inactive until they have verified their email. The rest I think I will manage on my own.

1
  • Doesn't WordPress do this by default?
    – Flimm
    May 29, 2019 at 17:04

1 Answer 1

13

I had a very similar problem which I solved the other day. In my case I wanted to allow users to choose their own password, and then activate their account via email. There's alot to this, so I'll just outline how to I achieved the e-mail verification.

First, I used user_register (runs when a user is registered) and created a key (e.g. hashed the time, user's email address and random string etc) and stored this key in the usermeta table. This will be deleted when the user activates their account.

To prevent an non-activated user from logging in, I added extra checks to the log-in, using the hook authenticate. For instance:

Edit As per the comments, the authenticate filter should return an WP_Error object for failure, otherwise, return null. wp_authenticate_username_password runs after this function, and if passed a WP_User object it doesn't perform any authentication checks, and assumes they have been done.

The edited code returns whatever was passed to it, or an WP_Error object if the activation key exists (i.e. the user has yet to activate their account).

add_filter( 'authenticate', 'wpse32218_check_for_key', 10, 3 );
function wpse32218_check_for_key( $user, $username, $password ){
    $user_obj = get_user_by('login', $username );

    if ($username!=''){
        $value = get_user_meta($user->ID, 'confirmed', true);
        if($value!=null){
            $user = new WP_Error( 'denied', __("<strong>ERROR</strong>: You need to activate your account.".$value."") );//create an error
            remove_action('authenticate', 'wp_authenticate_username_password', 20); //key found - don't proceed!
        }
    }
    return $user;
}

(you can use shake_error_codes to cause the log-in box to shake if the key is found if you like :D).

Then, in your plug-in, you will need to override wp_new_user_notification (which is a pluggable function present in /wp_includes/pluggable.php). This function sends the email to the new user and to the admin.

Copy the function into your plugin, inside

if ( !function_exists('wp_new_user_notification') ) :
    //Define your wp_new_user_notification function here
endif;

and then adapt it, so it retrieves and includes the activation key in the message to the user.

For the project I was working, I made a link from the activation key that the user could click to activate their account. E.g if their key was 01234ABCDE: http://www.example.com?confirm=01234ABCDE.

Using the filter query_vars I registered the variable 'confirm' with WordPress. Then with the template_include filter, whenever that variable is set (e.g. as above) I redirect the user to confirm.php (a template file sitting in my theme directory).

This template attempts to retrieve the user with the corresponding key. If it finds them, it deletes the key. They are now activated and able to log-in. If it doesn't it displays an error message (key doesn't exist or account has been activated). If there are multiple users with the same activation key (they shouldn't be!) it throws up an error also.

6
  • Wow, thanks! I'm sure I'll get this implemented tonight already with all your help.
    – ProfK
    Oct 27, 2011 at 16:31
  • Just a heads up. A very serious heads up! I used this code in a small plugin that I developed to display two password fields.(The 2nd for confirmation that they matched), on the registration form so that users could choose their own. After activating the plugin and testing I found that users were able to enter any combination of text for a password. Not the one they chose originally. Very dangerous. After some poking around it was the exact block of code that was causing this. I am now doing without this code.
    – user13133
    Feb 14, 2012 at 19:33
  • 1
    Phil's heads up is right, this is seriously flawed code. But it's easy to fix. just remove the return $user and you'll patch the security hole.
    – user19112
    Aug 10, 2012 at 6:54
  • @Phil @Scott Thanks for pointing this out. I've corrected the code. If wp_authenticate_username_password is passed a user object it skips authentication. The new function returns whatever it is given, and only an error object if the account is not activated. This allows for plug-ins to implement their own authentication function that runs before this one. Aug 10, 2012 at 9:54
  • @StephenHarris have you considered sharing this as a plugin? AFAIK there's nothing like it available right now. Personally, I cannot stop my other coding to start working in PHP. A plugin like this would be a huge help. Thanks! Jan 28, 2013 at 22:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.