Make WordPress Core

Changeset 50129

Timestamp:
02/01/2021 10:11:46 PM (4 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.

Location:
trunk/src
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/admin/user-profile.js

    r50001 r50129  
    33 */
    44
    5 /* global ajaxurl, pwsL10n */
     5/* global ajaxurl, pwsL10n */
    66(function($) {
    77    var updateLock = false,
     
    9090            }
    9191        });
     92
     93
     94
     95
     96
     97
     98
     99
     100
     101
     102
     103
     104
     105
     106
     107
     108
     109
     110
     111
     112
     113
     114
     115
     116
     117
     118
     119
     120
     121
     122
     123
     124
     125
     126
     127
     128
     129
     130
     131
     132
     133
     134
     135
     136
     137
     138
     139
     140
     141
     142
     143
     144
     145
     146
     147
     148
     149
     150
     151
     152
     153
    92154    }
    93155
     
    370432
    371433        bindPasswordForm();
     434
    372435    });
    373436
  • trunk/src/wp-admin/admin-ajax.php

    r49154 r50129  
    141141    'health-check-get-sizes',
    142142    'toggle-auto-updates',
     143
    143144);
    144145
  • trunk/src/wp-admin/includes/ajax-actions.php

    r49193 r50129  
    53995399    wp_send_json_success();
    54005400}
     5401
     5402
     5403
     5404
     5405
     5406
     5407
     5408
     5409
     5410
     5411
     5412
     5413
     5414
     5415
     5416
     5417
     5418
     5419
     5420
     5421
     5422
     5423
     5424
     5425
     5426
     5427
     5428
     5429
     5430
  • trunk/src/wp-admin/includes/class-wp-users-list-table.php

    r49944 r50129  
    275275        }
    276276
     277
     278
     279
     280
     281
    277282        return $actions;
    278283    }
     
    468473                    __( 'View' )
    469474                );
     475
     476
     477
     478
     479
    470480            }
    471481
  • trunk/src/wp-admin/user-edit.php

    r50006 r50129  
    610610</tr>
    611611<?php endif; ?>
     612
     613
     614
     615
     616
     617
     618
     619
     620
     621
     622
     623
     624
     625
     626
     627
     628
     629
     630
     631
     632
    612633
    613634        <?php
  • trunk/src/wp-admin/users.php

    r49944 r50129  
    203203                'delete_count' => $delete_count,
    204204                'update'       => $update,
     205
     206
     207
     208
     209
     210
     211
     212
     213
     214
     215
     216
     217
     218
     219
     220
     221
     222
     223
     224
     225
     226
     227
     228
     229
     230
     231
     232
     233
     234
     235
     236
     237
     238
     239
     240
     241
     242
     243
     244
    205245            ),
    206246            $redirect
     
    507547                    $messages[] = '<div id="message" class="updated notice is-dismissible"><p>' . $message . '</p></div>';
    508548                    break;
     549
     550
     551
     552
     553
     554
     555
     556
     557
     558
    509559                case 'promote':
    510560                    $messages[] = '<div id="message" class="updated notice is-dismissible"><p>' . __( 'Changed roles.' ) . '</p></div>';
  • trunk/src/wp-includes/functions.php

    r50037 r50129  
    77827782    return abs( (float) $expected - (float) $actual ) <= $precision;
    77837783}
     7784
     7785
     7786
     7787
     7788
     7789
     7790
     7791
     7792
     7793
     7794
     7795
     7796
     7797
     7798
     7799
     7800
     7801
     7802
     7803
     7804
     7805
     7806
     7807
     7808
     7809
     7810
     7811
     7812
     7813
     7814
     7815
     7816
     7817
     7818
     7819
     7820
     7821
     7822
     7823
     7824
     7825
     7826
     7827
     7828
     7829
     7830
     7831
     7832
     7833
     7834
     7835
     7836
     7837
     7838
     7839
     7840
     7841
     7842
     7843
     7844
     7845
     7846
     7847
     7848
     7849
     7850
     7851
     7852
     7853
     7854
     7855
     7856
     7857
     7858
     7859
     7860
     7861
     7862
     7863
     7864
     7865
     7866
     7867
     7868
     7869
     7870
     7871
     7872
     7873
     7874
     7875
     7876
     7877
     7878
     7879
     7880
     7881
     7882
     7883
     7884
     7885
     7886
     7887
     7888
     7889
     7890
     7891
     7892
     7893
     7894
     7895
     7896
     7897
     7898
     7899
     7900
     7901
     7902
     7903
     7904
     7905
     7906
     7907
     7908
     7909
     7910
     7911
     7912
     7913
     7914
     7915
     7916
     7917
     7918
     7919
     7920
     7921
     7922
     7923
     7924
     7925
     7926
     7927
     7928
     7929
     7930
     7931
     7932
     7933
     7934
     7935
     7936
     7937
     7938
     7939
     7940
     7941
     7942
     7943
     7944
     7945
     7946
     7947
     7948
     7949
     7950
     7951
     7952
  • trunk/src/wp-includes/script-loader.php

    r50048 r50129  
    10791079    $scripts->add( 'user-profile', "/wp-admin/js/user-profile$suffix.js", array( 'jquery', 'password-strength-meter', 'wp-util' ), false, 1 );
    10801080    $scripts->set_translations( 'user-profile' );
     1081
     1082
     1083
     1084
     1085
     1086
     1087
     1088
     1089
    10811090
    10821091    $scripts->add( 'language-chooser', "/wp-admin/js/language-chooser$suffix.js", array( 'jquery' ), false, 1 );
  • trunk/src/wp-login.php

    r50117 r50129  
    359359    <meta name="viewport" content="width=device-width" />
    360360    <?php
    361 }
    362 
    363 /**
    364  * Handles sending a password retrieval email to a user.
    365  *
    366  * @since 2.5.0
    367  *
    368  * @return true|WP_Error True when finished, WP_Error object on error.
    369  */
    370 function retrieve_password() {
    371     $errors    = new WP_Error();
    372     $user_data = false;
    373 
    374     if ( empty( $_POST['user_login'] ) || ! is_string( $_POST['user_login'] ) ) {
    375         $errors->add( 'empty_username', __( '<strong>Error</strong>: Please enter a username or email address.' ) );
    376     } elseif ( strpos( $_POST['user_login'], '@' ) ) {
    377         $user_data = get_user_by( 'email', trim( wp_unslash( $_POST['user_login'] ) ) );
    378         if ( empty( $user_data ) ) {
    379             $errors->add( 'invalid_email', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
    380         }
    381     } else {
    382         $login     = trim( wp_unslash( $_POST['user_login'] ) );
    383         $user_data = get_user_by( 'login', $login );
    384     }
    385 
    386     /**
    387      * Filters the user data during a password reset request.
    388      *
    389      * Allows, for example, custom validation using data other than username or email address.
    390      *
    391      * @since 5.7.0
    392      *
    393      * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
    394      * @param WP_Error      $errors    A WP_Error object containing any errors generated
    395      *                                 by using invalid credentials.
    396      */
    397     $user_data = apply_filters( 'lostpassword_user_data', $user_data, $errors );
    398 
    399     /**
    400      * Fires before errors are returned from a password reset request.
    401      *
    402      * @since 2.1.0
    403      * @since 4.4.0 Added the `$errors` parameter.
    404      * @since 5.4.0 Added the `$user_data` parameter.
    405      *
    406      * @param WP_Error      $errors    A WP_Error object containing any errors generated
    407      *                                 by using invalid credentials.
    408      * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
    409      */
    410     do_action( 'lostpassword_post', $errors, $user_data );
    411 
    412     /**
    413      * Filters the errors encountered on a password reset request.
    414      *
    415      * The filtered WP_Error object may, for example, contain errors for an invalid
    416      * username or email address. A WP_Error object should always be returned,
    417      * but may or may not contain errors.
    418      *
    419      * If any errors are present in $errors, this will abort the password reset request.
    420      *
    421      * @since 5.5.0
    422      *
    423      * @param WP_Error      $errors    A WP_Error object containing any errors generated
    424      *                                 by using invalid credentials.
    425      * @param WP_User|false $user_data WP_User object if found, false if the user does not exist.
    426      */
    427     $errors = apply_filters( 'lostpassword_errors', $errors, $user_data );
    428 
    429     if ( $errors->has_errors() ) {
    430         return $errors;
    431     }
    432 
    433     if ( ! $user_data ) {
    434         $errors->add( 'invalidcombo', __( '<strong>Error</strong>: There is no account with that username or email address.' ) );
    435         return $errors;
    436     }
    437 
    438     // Redefining user_login ensures we return the right case in the email.
    439     $user_login = $user_data->user_login;
    440     $user_email = $user_data->user_email;
    441     $key        = get_password_reset_key( $user_data );
    442 
    443     if ( is_wp_error( $key ) ) {
    444         return $key;
    445     }
    446 
    447     if ( is_multisite() ) {
    448         $site_name = get_network()->site_name;
    449     } else {
    450         /*
    451          * The blogname option is escaped with esc_html on the way into the database
    452          * in sanitize_option. We want to reverse this for the plain text arena of emails.
    453          */
    454         $site_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
    455     }
    456 
    457     $message = __( 'Someone has requested a password reset for the following account:' ) . "\r\n\r\n";
    458     /* translators: %s: Site name. */
    459     $message .= sprintf( __( 'Site Name: %s' ), $site_name ) . "\r\n\r\n";
    460     /* translators: %s: User login. */
    461     $message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n";
    462     $message .= __( 'If this was a mistake, ignore this email and nothing will happen.' ) . "\r\n\r\n";
    463     $message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
    464     $message .= network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . "\r\n\r\n";
    465 
    466     $requester_ip = $_SERVER['REMOTE_ADDR'];
    467     if ( $requester_ip ) {
    468         $message .= sprintf(
    469             /* translators: %s: IP address of password reset requester. */
    470             __( 'This password reset request originated from the IP address %s.' ),
    471             $requester_ip
    472         ) . "\r\n";
    473     }
    474 
    475     /* translators: Password reset notification email subject. %s: Site title. */
    476     $title = sprintf( __( '[%s] Password Reset' ), $site_name );
    477 
    478     /**
    479      * Filters the subject of the password reset email.
    480      *
    481      * @since 2.8.0
    482      * @since 4.4.0 Added the `$user_login` and `$user_data` parameters.
    483      *
    484      * @param string  $title      Email subject.
    485      * @param string  $user_login The username for the user.
    486      * @param WP_User $user_data  WP_User object.
    487      */
    488     $title = apply_filters( 'retrieve_password_title', $title, $user_login, $user_data );
    489 
    490     /**
    491      * Filters the message body of the password reset mail.
    492      *
    493      * If the filtered message is empty, the password reset email will not be sent.
    494      *
    495      * @since 2.8.0
    496      * @since 4.1.0 Added `$user_login` and `$user_data` parameters.
    497      *
    498      * @param string  $message    Email message.
    499      * @param string  $key        The activation key.
    500      * @param string  $user_login The username for the user.
    501      * @param WP_User $user_data  WP_User object.
    502      */
    503     $message = apply_filters( 'retrieve_password_message', $message, $key, $user_login, $user_data );
    504 
    505     if ( $message && ! wp_mail( $user_email, wp_specialchars_decode( $title ), $message ) ) {
    506         $errors->add(
    507             'retrieve_password_email_failure',
    508             sprintf(
    509                 /* translators: %s: Documentation URL. */
    510                 __( '<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>.' ),
    511                 esc_url( __( 'https://wordpress.org/support/article/resetting-your-password/' ) )
    512             )
    513         );
    514         return $errors;
    515     }
    516 
    517     return true;
    518361}
    519362
Note: See TracChangeset for help on using the changeset viewer.