Make WordPress Core


Ignore:
Timestamp:
02/01/2021 10:11:46 PM (6 years ago)
Author:
adamsilverstein
Message:

Users: enable admins to send users a reset password link.

Add a feature so Admins can send users a 'password reset' email. This doesn't change the password or force a password change. It only emails the user the password reset link.

The feature appears in several places:

  • A "Send Reset Link" button on user profile screen.
  • A "Send password reset" option in the user list bulk action dropdown.
  • A "Send password reset" quick action when hovering over a username in the user list.

Props Ipstenu, DrewAPicture, eventualo, wonderboymusic, knutsp, ericlewis, afercia, JoshuaWold, johnbillion, paaljoachim, hedgefield.
Fixes #34281.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/functions.php

    r50037 r50129  
    77827782        return abs( (float) $expected - (float) $actual ) <= $precision;
    77837783}
     7784
     7785/**
     7786 * Handles sending a password retrieval email to a user.
     7787 *
     7788 * @since 2.5.0
     7789 * @since 5.7.0 Added `$user_login` parameter.
     7790 *
     7791 * Note: prior to 5.7.0 this function was in wp_login.php.
     7792 *
     7793 * @global wpdb         $wpdb       WordPress database abstraction object.
     7794 * @global PasswordHash $wp_hasher  Portable PHP password hashing framework.
     7795 *
     7796 * @param  string       $user_login Optional user_login, default null. Uses
     7797 *                                  `$_POST['user_login']` if `$user_login` not set.
     7798 * @return true|WP_Error True when finished, WP_Error object on error.
     7799 */
     7800function retrieve_password( $user_login = null ) {
     7801        $errors    = new WP_Error();
     7802        $user_data = false;
     7803
     7804        // Use the passed $user_login if available, otherwise use $_POST['user_login'].
     7805        if ( ! $user_login && ! empty( $_POST['user_login'] ) ) {
     7806                $user_login = $_POST['user_login'];
     7807        }
     7808
     7809        if ( empty( $user_login ) ) {
     7810                $errors->add( 'empty_username', __( '<strong>Error</strong>: Please enter a username or email address.' ) );
     7811        } elseif ( strpos( $user_login, '@' ) ) {
     7812                $user_data = get_user_by( 'email', trim( wp_unslash( $user_login ) ) );
     7813                if ( empty( $user_data ) ) {
     7814                        $errors->add( 'invalid_email', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
     7815                }
     7816        } else {
     7817                $user_data = get_user_by( 'login', trim( wp_unslash( $user_login ) ) );
     7818        }
     7819
     7820        /**
     7821         * Filters the user data during a password reset request.
     7822         *
     7823         * Allows, for example, custom validation using data other than username or email address.
     7824         *
     7825         * @since 5.7.0
     7826         *
     7827         * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
     7828         * @param WP_Error      $errors    A WP_Error object containing any errors generated
     7829         *                                 by using invalid credentials.
     7830         */
     7831        $user_data = apply_filters( 'lostpassword_user_data', $user_data, $errors );
     7832
     7833        /**
     7834         * Fires before errors are returned from a password reset request.
     7835         *
     7836         * @since 2.1.0
     7837         * @since 4.4.0 Added the `$errors` parameter.
     7838         * @since 5.4.0 Added the `$user_data` parameter.
     7839         *
     7840         * @param WP_Error      $errors    A WP_Error object containing any errors generated
     7841         *                                 by using invalid credentials.
     7842         * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
     7843         */
     7844        do_action( 'lostpassword_post', $errors, $user_data );
     7845
     7846        /**
     7847         * Filters the errors encountered on a password reset request.
     7848         *
     7849         * The filtered WP_Error object may, for example, contain errors for an invalid
     7850         * username or email address. A WP_Error object should always be returned,
     7851         * but may or may not contain errors.
     7852         *
     7853         * If any errors are present in $errors, this will abort the password reset request.
     7854         *
     7855         * @since 5.5.0
     7856         *
     7857         * @param WP_Error      $errors    A WP_Error object containing any errors generated
     7858         *                                 by using invalid credentials.
     7859         * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
     7860         */
     7861        $errors = apply_filters( 'lostpassword_errors', $errors, $user_data );
     7862
     7863        if ( $errors->has_errors() ) {
     7864                return $errors;
     7865        }
     7866
     7867        if ( ! $user_data ) {
     7868                $errors->add( 'invalidcombo', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
     7869                return $errors;
     7870        }
     7871
     7872        // Redefining user_login ensures we return the right case in the email.
     7873        $user_login = $user_data->user_login;
     7874        $user_email = $user_data->user_email;
     7875        $key        = get_password_reset_key( $user_data );
     7876
     7877        if ( is_wp_error( $key ) ) {
     7878                return $key;
     7879        }
     7880
     7881        if ( is_multisite() ) {
     7882                $site_name = get_network()->site_name;
     7883        } else {
     7884                /*
     7885                 * The blogname option is escaped with esc_html on the way into the database
     7886                 * in sanitize_option. We want to reverse this for the plain text arena of emails.
     7887                 */
     7888                $site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
     7889        }
     7890
     7891        $message = __( 'Someone has requested a password reset for the following account:' ) . "\r\n\r\n";
     7892        /* translators: %s: Site name. */
     7893        $message .= sprintf( __( 'Site Name: %s' ), $site_name ) . "\r\n\r\n";
     7894        /* translators: %s: User login. */
     7895        $message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n";
     7896        $message .= __( 'If this was a mistake, ignore this email and nothing will happen.' ) . "\r\n\r\n";
     7897        $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
     7898        $message .= network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . "\r\n\r\n";
     7899
     7900        $requester_ip = $_SERVER['REMOTE_ADDR'];
     7901        if ( $requester_ip ) {
     7902                $message .= sprintf(
     7903                        /* translators: %s: IP address of password reset requester. */
     7904                        __( 'This password reset request originated from the IP address %s.' ),
     7905                        $requester_ip
     7906                ) . "\r\n";
     7907        }
     7908
     7909        /* translators: Password reset notification email subject. %s: Site title. */
     7910        $title = sprintf( __( '[%s] Password Reset' ), $site_name );
     7911
     7912        /**
     7913         * Filters the subject of the password reset email.
     7914         *
     7915         * @since 2.8.0
     7916         * @since 4.4.0 Added the `$user_login` and `$user_data` parameters.
     7917         *
     7918         * @param string  $title      Email subject.
     7919         * @param string  $user_login The username for the user.
     7920         * @param WP_User $user_data  WP_User object.
     7921         */
     7922        $title = apply_filters( 'retrieve_password_title', $title, $user_login, $user_data );
     7923
     7924        /**
     7925         * Filters the message body of the password reset mail.
     7926         *
     7927         * If the filtered message is empty, the password reset email will not be sent.
     7928         *
     7929         * @since 2.8.0
     7930         * @since 4.1.0 Added `$user_login` and `$user_data` parameters.
     7931         *
     7932         * @param string  $message    Email message.
     7933         * @param string  $key        The activation key.
     7934         * @param string  $user_login The username for the user.
     7935         * @param WP_User $user_data  WP_User object.
     7936         */
     7937        $message = apply_filters( 'retrieve_password_message', $message, $key, $user_login, $user_data );
     7938
     7939        if ( $message && ! wp_mail( $user_email, wp_specialchars_decode( $title ), $message ) ) {
     7940                $errors->add(
     7941                        'retrieve_password_email_failure',
     7942                        sprintf(
     7943                                /* translators: %s: Documentation URL. */
     7944                                __( '<strong>Error</strong>: The email could not be sent. Your site may not be correctly configured to send emails. <a href="%s">Get support for resetting your password</a>.' ),
     7945                                esc_url( __( 'https://wordpress.org/support/article/resetting-your-password/' ) )
     7946                        )
     7947                );
     7948                return $errors;
     7949        }
     7950
     7951        return true;
     7952}
Note: See TracChangeset for help on using the changeset viewer.