Here is a simple method for allowing users to log in with either their username or their email address.
This process allows the user to log in using either their username or their email address. It’s not difficult to implement and leaves you with a clean process where you don’t have to worry about what to do when users change their email address.
The Process
The WP-Members login function uses the WP function wp_signon. This process filters the user authentication that happens as part of wp_signon just before it has a user to validate. It returns the user info to the wp_signon function to complete authentication.
So, we can use the WP filter hook “authenticate” to get the user’s account information with the WP function get_user_by. get_user_by allows us to get the user’s username for authentication if we have another piece of information to match up the account. We use get_user_by to first check by username to see if the user has input a valid username. If that returns null, then we check by email. That will provide us with a potential user account, and if not, then it returns a login error.
Next we need to make sure that the provided password matches the password for the user account. We can do that with the wp_check_password function. This function takes the provided (plain text) password and compares it with the stored (hashed) password for validation. If the hash validates, then we can return the user for login. Otherwise, we return a null value which will in turn cause the login to fail.
Adding the following to your functions.php file will handle the process:
add_filter( 'authenticate', 'my_login_with_email', 10, 3 ); function my_login_with_email( $user=null, $username, $password ){ // First, check by username. $user = get_user_by( 'login', $username ); // If the username is invalid, check by email. if( ! $user ) { $user = get_user_by( 'email', $username ); } // Validate the password. if( $user ) { if( wp_check_password( $password, $user->user_pass ) ) { // If password checks out, return a valid login. return $user; } } // Return a failed login. return new WP_Error( 'login', "Login Failed" ); }
Provide a Clean User Experience
Of course if you do this, you will want to let the user know they can use their username OR their email address to log in. To do that, you need to filter the login form to provide an appropriate label for the form. Put plainly, we will change the label for “Username” to “Email or Username”.
The wpmem_inc_login_inputs filter allows us to do this very easily for the main body login form. This filter has a number of array elements for the form components, so we just need to change the first field (array location “0”) value for “name” (the field label). We can do that with the following filter:
add_filter( 'wpmem_inc_login_inputs', 'my_login_with_email_form' ); function my_login_with_email_form( $array ){ $array[0]['name'] = 'Email or Username'; return $array; }
The sidebar widget does not have this kind of option (YET!). So to change the sidebar label, we need to use the wpmem_sidebar_form filter to apply the PHP str_replace function to replace “Username” with “Email or Username” (or whatever you want it to read). However, there are two caveats here.
First, we don’t want to accidentally change any of the HTML code other than the displayed label. That could break the form. str_replace acts as a search/replace all kind of function. As a result, since there are other instances of “username” in the form’s HTML that we want untouched, I have chosen a more unique and specific string – “>Username<“. Note the “>” and “<“. These are the end of the opening label tag and the beginning of the closing label tag. That way we make sure to change only the part we want. (The whole tag looks like this: >label for=”username”<Username>/label<)
The other important caveat is that if you are running a translated site in another language, “>Username<” will be “>whatever-username-translates-to<“.
Also, notice that we need to make sure our replacement string (the second string given to the str_replace function) also puts in the correct “>” and “<” or your HTML tags won’t be right.
add_filter( 'wpmem_sidebar_form', 'my_login_with_email_sidebar' ); function my_login_with_email_sidebar( $string ){ return str_replace( '>Username<', '>Email or Username<', $string ); }
If you want to remove the “forgot username” link from the from the password reset form, you can do so with the wpmem_username_link_str filter using WP’s __return_empty_string to empty it:
add_filter( 'wpmem_username_link_str', '__return_empty_string' );
Other Considerations
This process would still require the user to create a (valid) username during the registration process. They just don’t need to remember it for logging in.
If you use this, you may also want to consider setting up the password reset to be reset with email only.