Статьи

Создание пользовательского потока WordPress. Часть 3. Сброс пароля

В первых двух уроках этой серии мы создали пользовательские страницы для входа в систему и регистрации нового пользователя. Теперь в процессе входа в систему осталась только одна часть для изучения и замены: что произойдет, если пользователь забудет свой пароль и захочет сбросить его.

В этом уроке мы рассмотрим последний шаг и завершим плагин Personalize Login, который мы создавали на протяжении всей серии.

Функциональность сброса пароля в WordPress соответствует тому, что стало более или менее стандартным подходом на современных веб-сайтах:

  1. Пользователь инициирует сброс, вводя свое имя пользователя или адрес электронной почты и запрашивая сброс пароля.
  2. Временный токен сброса пароля создается и сохраняется в пользовательских данных. Ссылка, содержащая этот токен, отправляется на адрес электронной почты пользователя.
  3. Пользователь нажимает на ссылку.
  4. На странице сброса пароля токен проверяется, и, если он соответствует данным пользователя, он получает возможность выбрать новый пароль.

Так же, как вход в систему и регистрация нового пользователя, эта функциональность обрабатывается через wp-login.php — и поэтому общая идея о том, как мы wp-login.php этот поток, теперь будет в основном знакома из предыдущих уроков.

Если вы еще не прочитали первые два учебника, лучше начать с первой части и пройти серию по порядку. Вы можете следовать учебному пособию во время написания кода самостоятельно или загрузить полный исходный код из связанного репозитория Github.

Теперь давайте начнем с замены первого экрана в потоке.

Сброс пароля начинается, когда пользователь заходит на вашу страницу входа, но не помнит, какой пароль он или она использовали для этого сайта.

Для этого мы разместили Забыли пароль? ссылка внизу формы входа в первую часть серии. По умолчанию на сайтах с поддержкой WordPress эта ссылка указывает на wp-login.php?action=lostpassword , страницу, которая выглядит следующим образом:

WordPress Забыли пароль?  Экран

Чтобы заменить эту страницу пользовательской, мы создадим функцию для перенаправления пользователя на нашу пользовательскую страницу и подключим эту функцию к действию WordPress.

В этом случае у нас есть два варианта на выбор: мы можем использовать действие lost_password , которое вызывается непосредственно перед визуализацией страницы, или действие, которое мы использовали в предыдущих уроках: login_form_{action} , на этот раз login_form_lostpassword .

Мы могли бы пойти обоими путями, но чтобы ограничить количество выполняемого ненужного кода, давайте выберем последний вариант.

Но сначала давайте создадим новую страницу.

Как вы помните, в первой части мы создали функцию для создания страниц WordPress при активации плагина, используя plugin_activated обратного вызова plugin_activated .

В этой функции добавьте определение новой страницы в конец массива $page_definitions . В потоке сброса пароля нам также понадобится вторая страница для выбора нового пароля. Итак, чтобы сэкономить время, давайте также добавим эту вторую страницу сейчас.

Вот весь массив для ясности (с добавлением двух последних определений страницы):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Information needed for creating the plugin’s pages
$page_definitions = array(
    ‘member-login’ => array(
        ‘title’ => __( ‘Sign In’, ‘personalize-login’ ),
        ‘content’ => ‘[custom-login-form]’
    ),
    ‘member-account’ => array(
        ‘title’ => __( ‘Your Account’, ‘personalize-login’ ),
        ‘content’ => ‘[account-info]’
    ),
    ‘member-register’ => array(
        ‘title’ => __( ‘Register’, ‘personalize-login’ ),
        ‘content’ => ‘[custom-register-form]’
    ),
    ‘member-password-lost’ => array(
        ‘title’ => __( ‘Forgot Your Password?’, ‘personalize-login’ ),
        ‘content’ => ‘[custom-password-lost-form]’
    ),
    ‘member-password-reset’ => array(
        ‘title’ => __( ‘Pick a New Password’, ‘personalize-login’ ),
        ‘content’ => ‘[custom-password-reset-form]’
    )
);

Обратный вызов активации плагина вызывается только тогда, когда плагин явно активирован, поэтому для создания этих новых страниц вам придется деактивировать плагин, а затем снова активировать его.

Теперь, когда страницы созданы, мы можем перенаправить пользователя на member-password-lost вместо wp-login?action=lostpassword .

Как я уже упоминал выше, мы будем использовать действие login_form_{action} или login_form_lostpassword чтобы обрезать их до того, как wp-login.php получит возможность отобразить версию по умолчанию «Забыли пароль?» экран.

В конструкторе плагина добавьте следующую строку:

1
add_action( ‘login_form_lostpassword’, array( $this, ‘redirect_to_custom_lostpassword’ ) );

Затем создайте функцию redirect_to_custom_lostpassword .

Эта функция будет проверять метод запроса: на данный момент мы будем работать только с запросами, отправленными с использованием метода GET поскольку они предназначены для отображения экрана. Мы посмотрим на то, что происходит в POST через некоторое время.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
/**
 * Redirects the user to the custom «Forgot your password?»
 * wp-login.php?action=lostpassword.
 */
public function redirect_to_custom_lostpassword() {
    if ( ‘GET’ == $_SERVER[‘REQUEST_METHOD’] ) {
        if ( is_user_logged_in() ) {
            $this->redirect_logged_in_user();
            exit;
        }
 
        wp_redirect( home_url( ‘member-password-lost’ ) );
        exit;
    }
}

Эта функция на самом деле такая же, как та, которую мы использовали для перенаправления пользователя на нашу пользовательскую страницу регистрации в предыдущем уроке, с заменой только перенаправления на страницу новой созданной нами страницы (хорошее место для некоторого рефакторинга в будущее, может быть?)

Теперь, если вы нажмете на Забыли пароль? На странице входа вы будете перенаправлены на пользовательскую страницу Забыли пароль? Теперь давайте создадим шорткод, чтобы добавить форму для инициации сброса пароля.

При создании страницы для инициации сброса пароля мы добавили шорткод [custom-lost-password-form] в его тело. Теперь, чтобы заменить шорткод на форму, давайте создадим обработчик шорткода.

В конструкторе плагина добавьте следующую строку:

1
add_shortcode( ‘custom-password-lost-form’, array( $this, ‘render_password_lost_form’ ) );

Затем создайте функцию для рендеринга формы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
/**
 * A shortcode for rendering the form used to initiate the password reset.
 *
 * @param array $attributes Shortcode attributes.
 * @param string $content The text content for shortcode.
 *
 * @return string The shortcode output
 */
public function render_password_lost_form( $attributes, $content = null ) {
    // Parse shortcode attributes
    $default_attributes = array( ‘show_title’ => false );
    $attributes = shortcode_atts( $default_attributes, $attributes );
 
    if ( is_user_logged_in() ) {
        return __( ‘You are already signed in.’, ‘personalize-login’ );
    } else {
        return $this->get_template_html( ‘password_lost_form’, $attributes );
    }
}

К настоящему времени большая часть этой функции вам уже знакома: сначала мы анализируем параметры show_title ( show_title используется, чтобы решить, следует ли отображать заголовок перед формой для инициации сброса пароля). Затем, если пользователь не вошел в систему, функция отображает шаблон, содержащий форму для инициации сброса пароля.

Давайте добавим этот шаблон сейчас. В каталоге templates создайте новый файл с именем password_lost_form.php . Затем добавьте следующий код в этот шаблон:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<div id=»password-lost-form» class=»widecolumn»>
    <?php if ( $attributes[‘show_title’] ) : ?>
        <h3><?php _e( ‘Forgot Your Password?’, ‘personalize-login’ );
    <?php endif;
 
    <p>
        <?php
            _e(
                «Enter your email address and we’ll send you a link you can use to pick a new password.»,
                ‘personalize_login’
            );
        ?>
    </p>
 
    <form id=»lostpasswordform» action=»<?php echo wp_lostpassword_url(); ?>» method=»post»>
        <p class=»form-row»>
            <label for=»user_login»><?php _e( ‘Email’, ‘personalize-login’ );
            <input type=»text» name=»user_login» id=»user_login»>
        </p>
 
        <p class=»lostpassword-submit»>
            <input type=»submit» name=»submit» class=»lostpassword-button»
                   value=»<?php _e( ‘Reset Password’, ‘personalize-login’ ); ?>»/>
        </p>
    </form>
</div>

Шаблон начинается с показа заголовка, если атрибут show_title имеет значение true ( строки 2-4 ).

Далее следуют некоторые инструкции в строках 6-13 и фактическая форма. Как вы увидите в строке 15 , форма будет размещена по URL-адресу, возвращенному функцией WordPress wp_lostpassword_url , по тому же URL-адресу, который мы видели выше, когда перенаправляли пользователя на нашу пользовательскую страницу.

Эта форма содержит только одно текстовое поле user_login ( строка 18 ). В этом поле функция сброса пароля по умолчанию в WordPress принимает имя пользователя или адрес электронной почты. Поскольку мы используем электронную почту в качестве имени пользователя, они оба одинаковы, поэтому мы будем запрашивать только адрес электронной почты в метке поля ( строка 17 ).

Когда вы добавите этот шаблон, нажмите « Забыли пароль?». ссылка на странице входа, вы увидите страницу, которая выглядит следующим образом (Если используется текущая тема WordPress по умолчанию, двадцать пятнадцать )

Пользовательский экран Забыли пароль?

Теперь, когда мы создали форму, пришло время посмотреть, что происходит, когда пользователь отправляет ее.

Чтобы мы могли правильно обрабатывать ошибки, не прибегая к хакерским атакам, нам нужно будет самим кодировать некоторые функции — используя как можно больше вспомогательных функций из wp-login.php , естественно.

Для этого мы добавим новую функцию для обработки запросов POST в действии login_form_lostpassword .

Эта функция будет использовать функцию retrieve_password определенную в wp-login.php для поиска пользователя и wp-login.php процедуры обновления пароля. Затем, в зависимости от того, были ли ошибки или нет, функция перенаправляет пользователя на правильную страницу: в случае ошибок, вернуться на страницу « Забыли пароль» и, в случае успеха, на страницу входа.

В конструкторе добавьте следующую строку:

1
add_action( ‘login_form_lostpassword’, array( $this, ‘do_password_lost’ ) );

Затем создайте функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
/**
 * Initiates password reset.
 */
public function do_password_lost() {
    if ( ‘POST’ == $_SERVER[‘REQUEST_METHOD’] ) {
        $errors = retrieve_password();
        if ( is_wp_error( $errors ) ) {
            // Errors found
            $redirect_url = home_url( ‘member-password-lost’ );
            $redirect_url = add_query_arg( ‘errors’, join( ‘,’, $errors->get_error_codes() ), $redirect_url );
        } else {
            // Email sent
            $redirect_url = home_url( ‘member-login’ );
            $redirect_url = add_query_arg( ‘checkemail’, ‘confirm’, $redirect_url );
        }
 
        wp_redirect( $redirect_url );
        exit;
    }
}

Функция начинается с проверки метода запроса (в строке 5 ). Поскольку нас интересует случай, когда отправляется форма с утерянным паролем, эта функция включается только тогда, когда находит запрос POST . GET запросы уже обрабатываются функцией redirect_to_custom_lostpassword мы создали ранее.

Затем в строке 6 мы вызываем функцию WordPress retrieve_password . Название функции немного вводит в заблуждение: функция на самом деле не получает пароль, а вместо этого проверяет данные из формы, а затем подготавливает учетную запись пользователя для сброса пароля, создав токен сброса пароля и отправив его по электронной почте пользователю.

Если есть ошибки ( строка 7 ), мы перенаправляем пользователя обратно на страницу member-password-lost , с кодами ошибок, передаваемыми в качестве параметра запроса ( строки 8-10 , с фактическим перенаправлением, выполненным в строке 17 ).

Если все идет хорошо, пользователь перенаправляется на страницу входа в систему с параметром запроса checkemail ( строки 12-14 ), чтобы мы могли показать сообщение пользователю.

Теперь, если вы отправите форму, все должно работать нормально. Но чтобы завершить работу с пользователем, нам нужно вернуться к шорткодам, отображающим утраченный пароль и к формам входа в систему, и показать сообщения об ошибках и об успехе.

Давайте начнем с позитива и добавим сообщение об успехе.

В функции render_login_form добавьте следующие строки где-нибудь перед вызовом get_template_html :

1
2
// Check if the user just requested a new password
$attributes[‘lost_password_sent’] = isset( $_REQUEST[‘checkemail’] ) && $_REQUEST[‘checkemail’] == ‘confirm’;

В шаблоне формы добавьте сообщение, используя атрибут сверху:

1
2
3
4
5
<?php if ( $attributes[‘lost_password_sent’] ) : ?>
    <p class=»login-info»>
        <?php _e( ‘Check your email for a link to reset your password.’, ‘personalize-login’ );
    </p>
<?php endif;

Теперь после успешного запуска сброса пароля форма входа в систему должна выглядеть следующим образом:

Инструкции по сбросу пароля отображаются на странице входа

Чтобы отобразить ошибки, мы вернемся к форме утерянного пароля.

Во-первых, в обработчике render_password_lost_form перед обработкой шаблона добавьте следующие строки, чтобы просмотреть коды ошибок и собрать соответствующие сообщения об ошибках в массиве $attributes['errors'] :

1
2
3
4
5
6
7
8
9
// Retrieve possible errors from request parameters
$attributes[‘errors’] = array();
if ( isset( $_REQUEST[‘errors’] ) ) {
    $error_codes = explode( ‘,’, $_REQUEST[‘errors’] );
 
    foreach ( $error_codes as $error_code ) {
        $attributes[‘errors’] []= $this->get_error_message( $error_code );
    }
}

Затем в шаблоне мы отрендерим ошибки:

1
2
3
4
5
6
7
<?php if ( count( $attributes[‘errors’] ) > 0 ) : ?>
    <?php foreach ( $attributes[‘errors’] as $error ) : ?>
        <p>
            <?php echo $error;
        </p>
    <?php endforeach;
<?php endif;

Наконец, добавьте сообщения об ошибках в нашу функцию get_error_messages :

1
2
3
4
5
6
7
8
// Lost password
 
case ’empty_username’:
    return __( ‘You need to enter your email address to continue.’, ‘personalize-login’ );
 
case ‘invalid_email’:
case ‘invalidcombo’:
    return __( ‘There are no users registered with this email address.’, ‘personalize-login’ );

Далее, чтобы завершить первый шаг в потоке сброса пароля, давайте посмотрим, как мы можем настроить электронную почту, отправляемую пользователю.

Как мы видели ранее, когда отправляется запрос на сброс пароля, в функции retrieve_password WordPress отправляет сообщение электронной почты, содержащее быстрые инструкции о том, что делать, и ссылку, которую можно использовать для завершения сброса пароля.

Сообщение короткое и к делу. Он делает то, что должен, но вы можете настроить его, чтобы придать ему индивидуальность и, возможно, сделать его более наглядным.

Текст по умолчанию жестко запрограммирован в wp-login.php , но перед отправкой сообщения WordPress дает разработчикам плагинов возможность заменить его, используя два фильтра.

Во-первых, чтобы заменить тело сообщения, вы можете использовать фильтр retrieve_password_message . Давайте сделаем это сейчас.

В конструкторе плагина добавьте следующую строку:

1
add_filter( ‘retrieve_password_message’, array( $this, ‘replace_retrieve_password_message’ ), 10, 4 );

Затем создайте функцию replace_retrieve_password_message :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * Returns the message body for the password reset mail.
 * Called through the retrieve_password_message filter.
 *
 * @param string $message Default mail message.
 * @param string $key The activation key.
 * @param string $user_login The username for the user.
 * @param WP_User $user_data WP_User object.
 *
 * @return string The mail message to send.
 */
public function replace_retrieve_password_message( $message, $key, $user_login, $user_data ) {
    // Create new message
    $msg = __( ‘Hello!’, ‘personalize-login’ ) .
    $msg .= sprintf( __( ‘You asked us to reset your password for your account using the email address %s.’, ‘personalize-login’ ), $user_login ) .
    $msg .= __( «If this was a mistake, or you didn’t ask for a password reset, just ignore this email and nothing will happen.», ‘personalize-login’ ) .
    $msg .= __( ‘To reset your password, visit the following address:’, ‘personalize-login’ ) .
    $msg .= site_url( «wp-login.php?action=rp&key=$key&login=» . rawurlencode( $user_login ), ‘login’ ) .
    $msg .= __( ‘Thanks!’, ‘personalize-login’ ) .
 
    return $msg;
}

Функция получает четыре параметра:

  • $message — версия $message по умолчанию для отправки пользователю. Мы проигнорируем этот параметр и создадим собственный текст с нуля.
  • $key — это токен, используемый для проверки запроса на сброс пароля пользователя. Он должен быть включен в ссылку для сброса пароля.
  • $user_login — это имя пользователя (в нашем случае это адрес электронной почты), также необходимое в ссылке для сброса пароля.
  • $user_data содержит некоторые данные о пользователе. Мы пока проигнорируем это, но вы можете изучить его дальше, если захотите.

Большая часть функции просто создает сообщение как серию конкатенаций строк. URL для завершения сброса пароля создается в строке 18 .

Для более полной настройки одной из идей было бы добавить поле настроек для редактирования содержимого сообщения восстановления пароля и использовать его вместо кодирования сообщения внутри функции таким образом.

Если хотите, вы можете использовать фильтр retrieve_password_title чтобы заменить заголовок сообщения электронной почты таким же образом. Функция фильтра принимает один параметр — заголовок по умолчанию для отправки пользователю и должна возвращать новый заголовок.

Еще один способ дальнейшей настройки заключается в замене всего сообщения и отправке вместо него сообщения HTML, например, с использованием метода, который я объяснил в предыдущем руководстве, об использовании Mandrill для отправки сообщений электронной почты из WordPress . В этом случае я бы использовал Mandrill API для отправки сообщения в функции фильтра выше и возвращал false, чтобы WordPress не пытался отправить письмо снова.

Вы завершили первый шаг процедуры сброса пароля: пользователь может попросить сбросить пароль, и процесс инициируется WordPress.

Далее мы рассмотрим, что происходит, когда пользователь нажимает на ссылку в письме для сброса пароля.

Как мы видели выше, после инициирования сброса пароля пользователь перенаправляется обратно на страницу входа в систему с инструкциями по проверке своей электронной почты.

В этом письме есть ссылка на wp-login.php с параметрами login и key для идентификации пользователя и проверки запроса на сброс пароля. Когда пользователь нажимает на ссылку, WordPress проверяет правильность имени пользователя и ключа, а затем, если все в порядке, позволяет пользователю установить новый пароль.

Функциональность работает хорошо, и мы будем использовать ее части, вызывая существующие вспомогательные функции в wp-login.php , но опять же, из-за того, как действия и фильтры организованы в коде сброса пароля, нам придется переписать некоторые кода, чтобы иметь возможность завершить настройку.

Во-первых, мы начнем с перенаправления пользователя на нашу страницу сброса пароля (которую мы создали в начале этого урока).

К настоящему времени это, вероятно, знакомо вам: так же, как мы делали действия при входе в систему и регистрации, а также на первой странице в потоке сброса пароля, мы будем использовать действие login_form_{action} для перенаправления действия сброса пароля нашим собственным пользовательским функциям, прежде чем WordPress сможет что-либо сделать

Есть два действия wp-login.php , которые используются для одной и той же функциональности, rp и resetpass , поэтому нам нужно перенаправить их обе на одну и ту же функцию redirect_to_custom_password_reset .

В конструкторе плагина добавьте следующие строки:

1
2
add_action( ‘login_form_rp’, array( $this, ‘redirect_to_custom_password_reset’ ) );
add_action( ‘login_form_resetpass’, array( $this, ‘redirect_to_custom_password_reset’ ) );

Затем создайте функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * Redirects to the custom password reset page, or the login page
 * if there are errors.
 */
public function redirect_to_custom_password_reset() {
    if ( ‘GET’ == $_SERVER[‘REQUEST_METHOD’] ) {
        // Verify key / login combo
        $user = check_password_reset_key( $_REQUEST[‘key’], $_REQUEST[‘login’] );
        if ( ! $user || is_wp_error( $user ) ) {
            if ( $user && $user->get_error_code() === ‘expired_key’ ) {
                wp_redirect( home_url( ‘member-login?login=expiredkey’ ) );
            } else {
                wp_redirect( home_url( ‘member-login?login=invalidkey’ ) );
            }
            exit;
        }
 
        $redirect_url = home_url( ‘member-password-reset’ );
        $redirect_url = add_query_arg( ‘login’, esc_attr( $_REQUEST[‘login’] ), $redirect_url );
        $redirect_url = add_query_arg( ‘key’, esc_attr( $_REQUEST[‘key’] ), $redirect_url );
 
        wp_redirect( $redirect_url );
        exit;
    }
}

Функция начинается с проверки, что это GET . POST запросы, отправленные на этот же URL, будут обработаны ниже.

Затем в строке 8 мы вызываем функцию WordPress check_password_reset_key чтобы убедиться, что параметры, переданные по ссылке сброса пароля, действительны. Если произошла ошибка, мы перенаправляем пользователя обратно на страницу входа с кодом ошибки в качестве параметра запроса ( строки 9-16 ). Мы добавим код для отображения ошибки в ближайшее время.

Если параметры были успешно проверены и пользователю разрешено обновлять свой пароль, функция продолжается, перенаправляя пользователя на нашу пользовательскую (все еще пустую) страницу сброса пароля, member-password-reset .

В строках 19-20 мы добавляем key параметров и входим в URL-адрес перенаправления, чтобы они были доступны для другой проверки, когда пользователь попытается установить новый пароль на следующем экране. Версия для сброса пароля WordPress по умолчанию использует для этого куки-файл, но ради учебника я решил использовать параметры запроса, чтобы облегчить выполнение кода.

Далее, давайте создадим пользовательскую версию формы сброса пароля.

Форма сброса пароля, отображаемая пользователю после нажатия на ссылку, полученную в электронном письме, по умолчанию выглядит следующим образом:

Экран сброса пароля WordPress

Это простая форма с двумя полями, pass1 и pass2 , одно для ввода пароля, а другое — для его pass1 pass2 , чтобы проверить, не было ли опечаток.

Для создания нашей пользовательской версии этой формы мы будем использовать шорткод.

Сначала добавьте следующую строку в конструктор плагина:

1
add_shortcode( ‘custom-password-reset-form’, array( $this, ‘render_password_reset_form’ ) );

Затем создайте функцию для рендеринга формы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * A shortcode for rendering the form used to reset a user’s password.
 *
 * @param array $attributes Shortcode attributes.
 * @param string $content The text content for shortcode.
 *
 * @return string The shortcode output
 */
public function render_password_reset_form( $attributes, $content = null ) {
    // Parse shortcode attributes
    $default_attributes = array( ‘show_title’ => false );
    $attributes = shortcode_atts( $default_attributes, $attributes );
 
    if ( is_user_logged_in() ) {
        return __( ‘You are already signed in.’, ‘personalize-login’ );
    } else {
        if ( isset( $_REQUEST[‘login’] ) && isset( $_REQUEST[‘key’] ) ) {
            $attributes[‘login’] = $_REQUEST[‘login’];
            $attributes[‘key’] = $_REQUEST[‘key’];
 
            // Error messages
            $errors = array();
            if ( isset( $_REQUEST[‘error’] ) ) {
                $error_codes = explode( ‘,’, $_REQUEST[‘error’] );
 
                foreach ( $error_codes as $code ) {
                    $errors []= $this->get_error_message( $code );
                }
            }
            $attributes[‘errors’] = $errors;
 
            return $this->get_template_html( ‘password_reset_form’, $attributes );
        } else {
            return __( ‘Invalid password reset link.’, ‘personalize-login’ );
        }
    }
}

Ядро этой функции начинается со строки 17 , где мы проверяем наличие параметров идентификации пользователя login и key. Если нет, ссылка для сброса пароля недействительна, и мы просто выводим сообщение об ошибке ( строка 34 ).

Если проверка в порядке, две переменные добавляются в массив $attributes чтобы сделать их доступными для шаблона формы ( строки 18-19 ).

Затем в строках 21-30 мы уже готовимся к ошибкам, которые могут возникнуть при отправке формы, используя тот же метод передачи ошибок, что и в предыдущих формах учебника.

Наконец, в строке 32 функция читает шаблон и возвращает его в WordPress для рендеринга.

Давайте создадим шаблон дальше. В каталоге templates создайте новый файл и назовите его password_reset_form.php . Добавьте следующий контент:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<div id=»password-reset-form» class=»widecolumn»>
    <?php if ( $attributes[‘show_title’] ) : ?>
        <h3><?php _e( ‘Pick a New Password’, ‘personalize-login’ );
    <?php endif;
 
    <form name=»resetpassform» id=»resetpassform» action=»<?php echo site_url( ‘wp-login.php?action=resetpass’ ); ?>» method=»post» autocomplete=»off»>
        <input type=»hidden» id=»user_login» name=»rp_login» value=»<?php echo esc_attr( $attributes[‘login’] ); ?>» autocomplete=»off» />
        <input type=»hidden» name=»rp_key» value=»<?php echo esc_attr( $attributes[‘key’] ); ?>» />
         
        <?php if ( count( $attributes[‘errors’] ) > 0 ) : ?>
            <?php foreach ( $attributes[‘errors’] as $error ) : ?>
                <p>
                    <?php echo $error;
                </p>
            <?php endforeach;
        <?php endif;
 
        <p>
            <label for=»pass1″><?php _e( ‘New password’, ‘personalize-login’ ) ?></label>
            <input type=»password» name=»pass1″ id=»pass1″ class=»input» size=»20″ value=»» autocomplete=»off» />
        </p>
        <p>
            <label for=»pass2″><?php _e( ‘Repeat new password’, ‘personalize-login’ ) ?></label>
            <input type=»password» name=»pass2″ id=»pass2″ class=»input» size=»20″ value=»» autocomplete=»off» />
        </p>
         
        <p class=»description»><?php echo wp_get_password_hint();
         
        <p class=»resetpass-submit»>
            <input type=»submit» name=»submit» id=»resetpass-button»
                   class=»button» value=»<?php _e( ‘Reset Password’, ‘personalize-login’ ); ?>» />
        </p>
    </form>
</div>

Форма начинается с необязательного заголовка, который отображается, если атрибут show_title имеет значение true ( строки 2-4 ).

Фактическая форма следует сразу после названия. Обратите внимание, что форма будет размещена на wp-login.php?action=resetpass ( строка 6 ), тот же URL-адрес, который используется в ссылке в сообщении электронной почты для сброса пароля, за исключением того, что в ссылке на электронную почту вместо resetpass используется короткая версия rp ,

В начале формы ( строки 7-8 ) мы устанавливаем два скрытых поля rp_key и rp_login для передачи key и параметров login в систему обработчику формы, который будет использовать их для проверки запроса на изменение пароля.

В строках 10-16 шаблон будет распечатывать ошибки, если они есть. Этот код точно такой же, как и в предыдущем шаблоне шорткода ранее в этом руководстве.

Два поля напечатаны в строках 18-25 , за которыми следуют некоторые инструкции по выбору надежного пароля и кнопка для отправки формы.

Вот как должна выглядеть форма сейчас:

Пользовательский экран сброса пароля

Когда пользователь отправляет форму, нажимая кнопку « Сбросить пароль» , ее содержимое отправляется на wp-login.php?action=resetpass , тот же URL-адрес, который мы использовали выше для перенаправления пользователя на нашу страницу сброса пароля.

Естественно, поскольку мы сами создали форму, мы могли бы использовать другой URL. Однако, сохраняя этот URL-адрес по умолчанию и используя действие login_form_resetpasslogin_form_rp , чтобы быть уверенным) для замены функциональности по умолчанию, мы можем быть уверены, что никто не закончит случайным вызовом версии по умолчанию для сброса пароля.

Для этого еще раз добавьте две строки в конструктор:

1
2
add_action( ‘login_form_rp’, array( $this, ‘do_password_reset’ ) );
add_action( ‘login_form_resetpass’, array( $this, ‘do_password_reset’ ) );

Затем создайте функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
 * Resets the user’s password if the password reset form was submitted.
 */
public function do_password_reset() {
    if ( ‘POST’ == $_SERVER[‘REQUEST_METHOD’] ) {
        $rp_key = $_REQUEST[‘rp_key’];
        $rp_login = $_REQUEST[‘rp_login’];
 
        $user = check_password_reset_key( $rp_key, $rp_login );
 
        if ( ! $user || is_wp_error( $user ) ) {
            if ( $user && $user->get_error_code() === ‘expired_key’ ) {
                wp_redirect( home_url( ‘member-login?login=expiredkey’ ) );
            } else {
                wp_redirect( home_url( ‘member-login?login=invalidkey’ ) );
            }
            exit;
        }
 
        if ( isset( $_POST[‘pass1’] ) ) {
            if ( $_POST[‘pass1’] != $_POST[‘pass2’] ) {
                // Passwords don’t match
                $redirect_url = home_url( ‘member-password-reset’ );
 
                $redirect_url = add_query_arg( ‘key’, $rp_key, $redirect_url );
                $redirect_url = add_query_arg( ‘login’, $rp_login, $redirect_url )
                $redirect_url = add_query_arg( ‘error’, ‘password_reset_mismatch’, $redirect_url );
 
                wp_redirect( $redirect_url );
                exit;
            }
 
            if ( empty( $_POST[‘pass1’] ) ) {
                // Password is empty
                $redirect_url = home_url( ‘member-password-reset’ );
 
                $redirect_url = add_query_arg( ‘key’, $rp_key, $redirect_url );
                $redirect_url = add_query_arg( ‘login’, $rp_login, $redirect_url );
                $redirect_url = add_query_arg( ‘error’, ‘password_reset_empty’, $redirect_url );
 
                wp_redirect( $redirect_url );
                exit;
            }
 
            // Parameter checks OK, reset password
            reset_password( $user, $_POST[‘pass1’] );
            wp_redirect( home_url( ‘member-login?password=changed’ ) );
        } else {
            echo «Invalid request.»;
        }
 
        exit;
    }
}

Функция начинается с проверки метода запроса, который должен быть POST ; GET запросы уже были обработаны функцией перенаправления выше.

Затем он собирает ключ и параметры входа в систему из данных формы и использует их для проверки ссылки для сброса пароля в строке 9 , используя функцию WordPress check_password_reset_key (ту же функцию, которую мы уже использовали в функции перенаправления).

В lines 10-18 мы снова проверяем возможные ошибки при проверке ключа сброса пароля, перенаправляя пользователя на страницу « Забыли пароль?». страница для отрисовки ошибок.

Затем, если ключ сброса действителен, мы можем сосредоточиться на форме.

Сначала функция проверяет, совпадают ли два пароля ( строки 21-31 ), а затем, что они не пусты ( строки 33-43 ). В обоих случаях пользователь перенаправляется обратно на нашу страницу сброса пароля, при этом key и параметры login включены в URL, чтобы пользователь мог повторить обновление пароля.

Наконец, если все проверки успешны (не стесняйтесь добавлять больше проверок, если хотите), функция сбрасывает пароль с помощью функции reset_passwordстроке 46 ) и перенаправляет пользователя на страницу входа с параметром password=changed добавленным к URL, чтобы показать уведомление.

Теперь пароль успешно обновлен, и все, что осталось, это показать уведомление об успехе и добавить сообщения об ошибках.

Сначала добавим уведомление. В функции render_login_form добавьте следующую проверку:

1
2
// Check if user just updated password
$attributes[‘password_updated’] = isset( $_REQUEST[‘password’] ) && $_REQUEST[‘password’] == ‘changed’;

Затем добавьте фактическое сообщение в шаблон, login_form.php , прямо перед отображением формы:

1
2
3
4
5
<?php if ( $attributes[‘password_updated’] ) : ?>
    <p class=»login-info»>
        <?php _e( ‘Your password has been changed. You can sign in now.’, ‘personalize-login’ );
    </p>
<?php endif;

Поскольку мы уже добавили поддержку рендеринга сообщений об ошибках выше, все, что осталось, это добавить описательные сообщения об ошибках в нашу функцию get_error_message .

Добавьте следующие строки прямо перед веткой по default в конструкции switch...case :

01
02
03
04
05
06
07
08
09
10
11
// Reset password
 
case ‘expiredkey’:
case ‘invalidkey’:
    return __( ‘The password reset link you used is not valid anymore.’, ‘personalize-login’ );
 
case ‘password_reset_mismatch’:
    return __( «The two passwords you entered don’t match.», ‘personalize-login’ );
     
case ‘password_reset_empty’:
    return __( «Sorry, we don’t accept empty passwords.», ‘personalize-login’ );

Это оно! Функция сброса пароля готова, и поэтому мы завершили настройку входа в WordPress: от регистрации нового пользователя до входа в систему и сброса утерянного пароля.

Я надеюсь, что серия предоставит вам достаточно инструментов, чтобы вы чувствовали себя хорошо подготовленными для дальнейшей настройки — например, добавив новый шаг в поток сброса пароля — и лучшего понимания того, что происходит внутри wp-login.php.

Теперь иди и настроить еще немного!