На прошлой неделе я уже опубликовал урок о том, как создать собственную форму авторизации в WordPress. Урок был очень простой и, казалось бы, надо идти по увеличению сложности и заняться формой регистрации.. но нет, сейчас мы рассмотрим самую сложную часть, связанную со страницами восстановления пароля — именно страницами, потому что в принципе их две — та, на которой вы вводите свой email и та, на которой вы устанавливаете новый пароль.
Однако я в свою очередь сделаю всё возможное, чтобы этот урок упростить.
Небольшая видео-демонстрация того, что мы сейчас будем делать:
На самом деле и тема и сам код довольно интересны, кроме того, я не встречал ещё хороших уроков об этом. Есть один урок на енвато, состоящий из двух частей, каждая из которых в свою очередь состоит из трёх шагов, у меня самого голова кругом пошла, когда я начал там разбираться.
Ну хватит болтовни, урок состоит из двух шагов, в первом мы создаём шорткод, а во втором — настраиваем редиректы и отправку письма. Весь код можете спокойно отправить в functions.php
текущей темы.
Прежде всего вставьте этот код.
add_shortcode( 'misha_custom_passreset', 'misha_render_pass_reset_form' ); // шорткод [misha_custom_passreset] function misha_render_pass_reset_form() { // если пользователь авторизован, просто выводим сообщение и выходим из функции if ( is_user_logged_in() ) { return sprintf( "Вы уже авторизованы на сайте. <a href='%s'>Выйти</a>.", wp_logout_url() ); } $return = ''; // переменная, в которую всё будем записывать // обработка ошибок, если вам нужны такие же стили уведомлений, как в видео, CSS-код прикладываю чуть ниже if ( isset( $_REQUEST['errno'] ) ) { $errors = explode( ',', $_REQUEST['errno'] ); foreach ( $errors as $error ) { switch ( $error ) { case 'empty_username': $return .= '<p class="errno">Вы не забыли указать свой email?</p>'; break; case 'password_reset_empty': $return .= '<p class="errno">Укажите пароль!</p>'; break; case 'password_reset_mismatch': $return .= '<p class="errno">Пароли не совпадают!</p>'; break; case 'invalid_email': case 'invalidcombo': $return .= '<p class="errno">На сайте не найдено пользователя с указанным email.</p>'; break; } } } // тем, кто пришёл сюда по ссылке из email, показываем форму установки нового пароля if ( isset( $_REQUEST['login'] ) && isset( $_REQUEST['key'] ) ) { $return .= '<h3>Укажите новый пароль</h3> <form name="resetpassform" id="resetpassform" action="' . site_url( 'wp-login.php?action=resetpass' ) . '" method="post" autocomplete="off"> <input type="hidden" id="user_login" name="login" value="' . esc_attr( $_REQUEST['login'] ) . '" autocomplete="off" /> <input type="hidden" name="key" value="' . esc_attr( $_REQUEST['key'] ) . '" /> <p> <label for="pass1">Новый пароль</label> <input type="password" name="pass1" id="pass1" class="input" size="20" value="" autocomplete="off" /> </p> <p> <label for="pass2">Повторите пароль</label> <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" /> </p> <p class="description">' . wp_get_password_hint() . '</p> <p class="resetpass-submit"> <input type="submit" name="submit" id="resetpass-button" class="button" value="Сбросить" /> </p> </form>'; // возвращаем форму и выходим из функции return $return; } // всем остальным - обычная форма сброса пароля (1-й шаг, где указываем email) $return .= ' <h3>Забыли пароль?</h3> <p>Укажите свой email, под которым вы зарегистрированы на сайте и на него будет отправлена информация о восстановлении пароля.</p> <form id="lostpasswordform" action="' . wp_lostpassword_url() . '" method="post"> <p class="form-row"> <label for="user_login">Email</label> <input type="text" name="user_login" id="user_login"> </p> <p class="lostpassword-submit"> <input type="submit" name="submit" class="lostpassword-button" value="Отправить" /> </p> </form>'; // возвращаем форму и выходим из функции return $return; }
Если код выше вам понятен, то вы заметили, что у нас будет одна страница WordPress для восстановления пароля — и когда мы указываем email для получения письма, и когда мы задаём новый пароль.
Поэтому теперь уже в админке WordPress переходим в Страницы > Добавить новую и вставляем в неё наш шорткод [misha_custom_passreset]
.
Если код из этой статьи вас пугает, рекомендую сделать всё 1 в 1, как на скриншоте.
После того, как я разлогинился (вышел из сайта) и перешёл непосредственно на эту страницу, у меня получилось следующее.
Ах да, чуть не забыл про CSS, вот он:
.errno{ background-color: #f4f4f4; padding: 10px 20px; border-left: 5px solid #fe0000; } .errno.success{ border-left-color:#0bb80b; }
А теперь код поинтереснее, и самое ужасное, что вам придётся настроить его под себя. Шучу, на самом деле ничего страшного тут не будет, единственное, что нужно сделать, это в начале каждой функции поменять ярлыки (slug) URL страницы восстановления пароля и страницы входа (прошлый урок) на те значения, которые решили использовать вы.
Если же вы так же создали у себя страницы с ярлыками forgot-pass
и login
, то вообще ничего менять не нужно.
/* * перенаправляем стандартную форму */ add_action( 'login_form_lostpassword', 'misha_pass_reset_redir' ); function misha_pass_reset_redir() { // если используете другой ярлык страницы сброса пароля, укажите здесь $forgot_pass_page_slug = '/forgot-pass'; // если используете другой ярлык страницы входа, укажите здесь $login_page_slug = '/login'; // если кто-то перешел на страницу сброса пароля // (!) именно перешел, а не отправил формой, // тогда перенаправляем на нашу кастомную страницу сброса пароля if ( 'GET' == $_SERVER['REQUEST_METHOD'] && !is_user_logged_in() ) { wp_redirect( site_url( $forgot_pass_page_slug ) ); exit; } else if ( 'POST' == $_SERVER['REQUEST_METHOD'] ) { // если же напротив, была отправлена форма // юзаем retrieve_password() // которая отправляет на почту ссылку сброса пароля // пользователю, который указан в $_POST['user_login'] $errors = retrieve_password(); if ( is_wp_error( $errors ) ) { // если возникли ошибки, возвращаем пользователя назад на форму $to = site_url( $forgot_pass_page_slug ); $to = add_query_arg( 'errno', join( ',', $errors->get_error_codes() ), $to ); } else { // если ошибок не было, перенаправляем на логин с сообщением об успехе $to = site_url( $login_page_slug ); $to = add_query_arg( 'errno', 'confirm', $to ); } // собственно сам редирект wp_redirect( $to ); exit; } } /* * Манипуляции уже после перехода по ссылке из письма */ add_action( 'login_form_rp', 'misha_to_custom_password_reset' ); add_action( 'login_form_resetpass', 'misha_to_custom_password_reset' ); function misha_to_custom_password_reset(){ $key = $_REQUEST['key']; $login = $_REQUEST['login']; // если используете другой ярлык страницы сброса пароля, укажите здесь $forgot_pass_page_slug = '/forgot-pass'; // если используете другой ярлык страницы входа, укажите здесь $login_page_slug = '/login'; // проверку соответствия ключа и логина проводим в обоих случаях if ( ( 'GET' == $_SERVER['REQUEST_METHOD'] || 'POST' == $_SERVER['REQUEST_METHOD'] ) && isset( $key ) && isset( $login ) ) { $user = check_password_reset_key( $key, $login ); if ( ! $user || is_wp_error( $user ) ) { if ( $user && $user->get_error_code() === 'expired_key' ) { wp_redirect( site_url( $login_page_slug . '?errno=expiredkey' ) ); } else { wp_redirect( site_url( $login_page_slug . '?errno=invalidkey' ) ); } exit; } } if ( 'GET' == $_SERVER['REQUEST_METHOD'] ) { $to = site_url( $forgot_pass_page_slug ); $to = add_query_arg( 'login', esc_attr( $login ), $to ); $to = add_query_arg( 'key', esc_attr( $key ), $to ); wp_redirect( $to ); exit; } elseif ( 'POST' == $_SERVER['REQUEST_METHOD'] ) { if ( isset( $_POST['pass1'] ) ) { if ( $_POST['pass1'] != $_POST['pass2'] ) { // если пароли не совпадают $to = site_url( $forgot_pass_page_slug ); $to = add_query_arg( 'key', esc_attr( $key ), $to ); $to = add_query_arg( 'login', esc_attr( $login ), $to ); $to = add_query_arg( 'errno', 'password_reset_mismatch', $to ); wp_redirect( $to ); exit; } if ( empty( $_POST['pass1'] ) ) { // если поле с паролем пустое $to = site_url( $forgot_pass_page_slug ); $to = add_query_arg( 'key', esc_attr( $key ), $to ); $to = add_query_arg( 'login', esc_attr( $login ), $to ); $to = add_query_arg( 'errno', 'password_reset_empty', $to ); wp_redirect( $to ); exit; } // тут кстати вы можете задать и свои проверки, например, чтобы длина пароля была 8 символов // с паролями всё окей, можно сбрасывать reset_password( $user, $_POST['pass1'] ); wp_redirect( site_url( $login_page_slug . '?errno=changed' ) ); } else { // если что-то пошло не так echo "Что-то пошло не так."; } exit; } }
Ну вот и всё, ссылки на описание некоторых из используемых функций вы найдёте чуть ниже под статьей. Кроме того, если у вас возник вопрос, вы всегда можете оставить его в комментариях, и он не останется без внимания.
Чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или войдите.
Миша, привет.
Отличная серия постов по форме входа на сайт.
Работает всё, за исключением одного:
Почему-то не корректно работает форма сброса пароля.
1. Когда ввожу в форме сброса пароля любой адрес полный, то появляется форма WP с сообщением "Пользователей с таким адресом e-mail не зарегистрировано."
2. Если ввожу любой текст в поле для e-mail, то тоже форма WP "Неверное имя пользователя или e-mail."
В представленном коде не нашел таких сообщений.
Может тут части кода нет для этой цели, поэтому берется встроенная форма?
В представленном примере в видео этот момент работает правильно.
Миша, а что по этому поводу?
У меня всё ок
Может это потому-что я использовал стартовую тему пустую при разработке?
А вы применили в уже готовой теме.
И в коде нет этих фраз к тому же...
в WordPress они есть.
Я применил в twenty fifteen — можете попробовать в ней, но не уверен, что причина в теме (вы же использовали пустую).
Всё заработало. Случайно часть кода не скопировал.
Возник вопрос:
Я вызываю форму входа через шорткод.
Хочу теперь убрать лейблы к input и вставить placeholder.
Я открыл wp-login.php и добавил в два инпута свои placeholder="текст", но они не отобразились.
Если в браузере изменить код, то все работает.
Т.е. базовые параметры инпутов подменяются что ли другими параметрами?
Подскажите пожалуйста, как сделать, чтобы placeholder появился?
В wp-login.php ничего редактировать не нужно. Можно через JS
И еще такие вопросики:
- можно ли убрать перезагрузку страницы при работе с формой?
- и как сделать запрет (редирект) в url на всё, что начинается с "wp-" (wp-admin, wp-login и аналогичные)?
с запретом и редиректом разобрался)
если следовать рекомендациям на блогах (везде одно и тоже) и вставить в functions.php код ниже, то форма входа перестает работать:
Миша, как с твоей формой выйти из этого положения, сохранив редирект с wp-....?
А не надо его вставлять, если не работает.
Админку блокируете этим способом, а wp-login.php оставьте в покое.
а защита сайта через переименование wp-admin / wp-login считаете нормальным решением, стоит ли этим заморачиваться ?
нет
Спасибо за замечательную статью и плагины! TrueMetabox'ом пользуюсь очень часто. А сейчас оплатил регистрацию по главной причине, чтобы написать этот камент:
Теперь по теме. В моем случае на 2-ом шаге на строках 74 и 74 пришлось изменить переменную $redirect_url на $to. Без этого - при переходе по ссылке из письма для установки нового пароля браузер бесконечно перенаправляется:
Долго искал в чём проблема, не мог разобраться. Но всё-таки получилось запустить :)
Если это опечатка - исправь, пожалуйста, в листинге выше на странице, чтобы другие не столкнулись с такой-же проблемой.
Привет, Александр,
спасибо огромное за этот комментарий, действительно, там косяк, видимо по какой-то причине я решил изменить название переменной, но заменил не везде :)
P.S. постараюсь в ближайшее время возобновить публикацию качественных и полезных статей на сайте!
Буду ждать! Очень хочется пост про кастомную страницу профиля :)
Т.е. про ту, которая находится за пределами админки?
Оу, оказывается уже есть такая ) Спасибо!
Да не за что)
Есть ли возможность, чтобы ошибки, при незаполнении чего-либо отображались внизу, а не сверху?
Думаю, что есть.
Но это не точно.
Приветствую. Спасибо за старания, узнал много нового из ваших статей. Не подскажете в чем может быть проблема? Скопировал код, все работает до момента когда скрипт пытается уже именно задать новый пароль юзеру. В ошибках выдает много, но там системные файлы, основное думаю это
Насколько я понимаю он не может получить юзера, хотя это условие отрабатывает, иначе меня бы редиректило еще до того как смог бы отправить форму я так понимаю.
Но почему то юзер в итоге оказывается NULL... Не подскажете в чем тут может быть проблема?
Аналогичная проблема. Не смогли решить ее?
Отвечаю на свой-же вопрос :)
Вероятно, некоторые детали восстановления пароля в WP с момента написания статьи изменились. Мы не получаем пользователя, потому что в момент перезаписи пароля (когда мы его ввели и отправили), объектов
$key
и$login
больше не существует. Поэтому получить объект пользователя не получится. Но эти данные можно получить из кукисов и массива$_POST
.Как можно решить эту проблему:
Все здорово, все работает, спасибо!
Огнище!
Привет Миша, можешь подсказать что не так, при вводе пароля на странице где работает шорткод восстановления и нажатия на кнопку: "Отправить" меня перебрасывает на страницу: /my-account/lost-password/ где опять просит ввести email для восстановления: "Lost your password? Please enter your username or email address. You will receive a link to create a new password via email."
Для чистоты эксперимента решил проверить все на twenty fifteen - не рабюотает. Непонял, не может быть. А оказывается может. У меня на сайте работает woocommerce после того как выключил плагин woocommerce все сразу заработало и на twenty fifteen и на остальных темах. Но как быть. Без woocommerce не получится, проект на нем работает, а с ним не работает кастомная форма восстановления пароля. Миша подскажи есть варианты решения под woocommerce?
Всем добра! Отвечаю на свой вопрос, возможно кому-то будет интересно. Дело в том что в WooCommerce есть свой кабинет пользователя и своя страница восстановления пароля. Поэтому-то я и столкнулся с проблемой переадресации. Решается это вот так: WooCommerce> Settings> Advanced. Здесь находим: Account endpoints и удаляем из поля Lost password то что там есть(оставляем поле пустым), сохраняем настройки и все прекрасно работает. Мише отдельный респект, за качественный контент.
Здравствуйте, Михаил!
Помогите пожалуйста решить проблему!
Если указываю в коде, как указано у Вас:
Все ошибки отображаются корректно, но при успешном вводе email меня перекидывает на страницу авторизации, без оповещения, что письмо отправлено.
Поменял код на этот:
И добавил вывод оповещения о отправки письма:
Но теперь при переходе по ссылке из письма форма смены пароля редиректит на форму авторизации.
Подскажите пожалуйста как быть?
Здравствуйте. Всё работало отлично пока что-то не обновилось и код слетел. Теперь добавляю всё обратно но при сбросе пароля меня перекидает на стандартную форму WP. Раньше всё работало на одной странице. Как заменить стандартную форму на свою?