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 Answer
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.
-
Wow, thanks! I'm sure I'll get this implemented tonight already with all your help.– ProfKOct 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.– user13133Feb 14, 2012 at 19:33
-
1Phil'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.– user19112Aug 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