Email verification for new users

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.