1

I'm working on a setup where user logins have to follow this format :

login : user-john@doe.com

Even though Wordpress has no problem creating such accounts, it seems they don't play well with the "Forgotten password" form :

enter image description here

The culprit is in wp-login.php :

function retrieve_password() {
    $errors = new WP_Error();
    if ( empty( $_POST['user_login'] ) || ! is_string( $_POST['user_login'] ) ) {
        $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Enter a username or email address.' ) );
    } elseif ( strpos( $_POST['user_login'], '@' ) ) {
        $user_data = get_user_by( 'email', trim( wp_unslash( $_POST['user_login'] ) ) );
        if ( empty( $user_data ) ) {
            $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: There is no account with that username or email address.' ) );
        }
    } else {
        $login     = trim( $_POST['user_login'] );
        $user_data = get_user_by( 'login', $login );
    }

Specifically this line :

} elseif ( strpos( $_POST['user_login'], '@' ) ) {

When Wordpress finds a @ in the login, it thinks that it's actually the email.

Is there a way to get around this without having to modifiy this core file ?

The two constraints I have is I cannot change the login format and the user has to submit his login (password reset calling the email field is not allowed, for reasons irrelevant to this tread)

3 Answers 3

2
+100

Create a custom template for forgot password and add forgot password page link to WordPress login page using theme functions.php. Please see the code given below and modify conditions as per your need.

    <?php 
/*
* Template Name: Forgot Password
*/

global $wpdb;

$error = '';
$success = '';

// check if we're in reset form
if( isset( $_POST['action'] ) && 'reset' == $_POST['action'] ) 
{
    $user_info = trim($_POST['user_login']);

    $user_by_email = get_user_by( 'email', $user_info ); 
    $user_by_username = get_user_by( 'login', $user_info ); 

    if( !empty( $user_by_email ) || !empty( $user_by_username ) ) {
        $valid_user = true;
    } else {
        $valid_user = false;
    }

    if( !$valid_user ) {
        $error = 'There is no user registered with that username or email address.';
    } else {

        $random_password = wp_generate_password( 12, false );
        $user = get_user_by( 'email', $email );

        $update_user = wp_update_user( array (
                'ID' => $user->ID, 
                'user_pass' => $random_password
            )
        );

        // if  update user return true then lets send user an email containing the new password
        if( $update_user ) {
            $to = $email;
            $subject = 'Your new password';
            $sender = get_option('name');

            $message = 'Your new password is: '.$random_password;

            $headers[] = 'MIME-Version: 1.0' . "\r\n";
            $headers[] = 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
            $headers[] = "X-Mailer: PHP \r\n";
            $headers[] = 'From: '.$sender.' < '.$email.'>' . "\r\n";

            $mail = wp_mail( $to, $subject, $message, $headers );
            if( $mail )
                $success = 'Check your email address for you new password.';

        } else {
            $error = 'Oops something went wrong updaing your account.';
        }

    }

    if( ! empty( $error ) )
        echo '<div class="message"><p class="error"><strong>ERROR:</strong> '. $error .'</p></div>';

    if( ! empty( $success ) )
        echo '<div class="error_login"><p class="success">'. $success .'</p></div>';
}
?>


<form method="post">
    <fieldset>
        <p>Please enter your username or email address. You will receive a link to create a new password via email.</p>
        <p><label for="user_login">Username or E-mail:</label>
            <?php $user_login = isset( $_POST['user_login'] ) ? $_POST['user_login'] : ''; ?>
            <input type="text" name="user_login" id="user_login" value="<?php echo $user_login; ?>" /></p>
        <p>
            <input type="hidden" name="action" value="reset" />
            <input type="submit" value="Get New Password" class="button" id="submit" />
        </p>
    </fieldset> 
</form> 

And add the code given below to change forgot password page link.

add_filter( 'lostpassword_url', 'my_lost_password_page', 10, 2 );
function my_lost_password_page( $lostpassword_url, $redirect ) {
    return 'your custom page link';
}
1
  • Thanks, I might follow that route as a temporary solution, on the long term it seems wisest to implement another login format (see @birgire's) answer.
    – mike23
    Jul 2, 2019 at 7:41
2

I would not recommend using the email address as username, for post authors, as this could expose the emails to the public.

If user-john@example.com has written any posts, the author archive will be accessible with:

https://example.com/author/user-johnexample-com/

or from the redirection of e.g.:

https://example.com/?author=123

The REST API users endpoint also outputs similar information for post authors.

Modifying an important part like the login flow, could also introduce technical dept to ensure the security and exposure is intact after each core/theme/plugin update.

1
  • You're right, in the long run that is probably the best thing to do, even if in this particular case scenario I'm working on the users actually want their email to be visible.
    – mike23
    Jul 2, 2019 at 7:44
0

Usernames typically should not contain any special characters, only letters, numbers and the underline ( _ ) should be allowed. If a login contains @, then it should be interpreted as an email.

I'm not sure what you meant by this:

When Wordpress finds a @ in the login, it thinks that it's actually the email.

If you are trying to implement custom login logics, you can create a page, assign a template to it and use your own code to reset password inside that page. After you are finished, you can use the lostpassword_url filter to redirect users to this page to reset their passwords.

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.