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

Стало:

Есть два пути решения такой задачи: редизайнить через css wp-login.php или полностью переписать страничку авторизации. Первое нам не подходило, поэтому было принято решение взять сложный путь.
Вы понимаете, что нарисовать и сверстать дизайн — это дело вторичное и по сути не является проблемой. Поэтому эту часть я опускаю и сразу перехожу к главному — обработчику формуляра.
Любопытство взяло вверх и решил я поизучать немного всю систему авториза WordPress. Нехитрая штука, но я не об этом. Решается поставленная задача очень просто 10-15 строками кода:
$creds = array();
$creds['user_login'] = $login;
$creds['user_password'] = $password;
$creds['remember'] = true;
$user = wp_signon( $creds, false );
if ( is_wp_error($user) ) {
echo $user->get_error_message();
} else {
wp_redirect('index.php');
}
Листинг 1. Пример авторизации в WordPress
В общих чертах это выглядит именно так. Всю проблему решает функция wp_signon ($credentials, $security_cookie). В коде все весьма просто: делаем массив с данными, полученными через $_POST и используем в функции.
Вторая часть кода проверяет были ли ошибки при авторизе и, если все нормально, то делает редирект, куда вы укажите.
Есть еще более сложный и извращенный способ. Можно вообще все разложить по полочкам, но его я не буду тут приводить. Только в конце поста вернусь и укажу полезные функции в решении подобных задач.
Подитоживая
Делаем html страничку с красивым формуляром. Пример html кода формуляра:
<form name="loginform" id="loginform" action="<?php get_option('home') ?>/loginhandle.php" method="post">
<label>Пользователь</label>
<p class="input-bg"><input type="text" name="log" id="log" class="input" value="" /></p>
<label>Пароль</label>
<p class="input-bg"><input type="password" name="user_pass" id="user_pass" class="input" value="" /></p>
<p class="forgetmenot"><input name="rememberme" type="checkbox" id="rememberme" value="forever" /> Запомнить меня</p>
<p class="submit">
<span><a href="<?php echo site_url('wp-login.php?action=lostpassword', 'login') ?>">Забыл пароль?</a></span>
<input type="submit" name="wp-submit" id="wp-submit" value="Войти" tabindex="100" />
<input type="hidden" name="redirect_to" value="http://<?php echo $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] ?>" />
<input type="hidden" name="testcookie" value="1" />
</p>
</form>
Листинг 2. Пример формуляра для авторизации с учетом WordPress фишек.
Я предпочитаю отдельно держать обработчики всех событий, формуляров. Поэтому использую ajax. В данном случае, через jquery нужно будет отправить формуляр в loginhandler.php.
define('HACK_404', true);
define('WP_USE_THEMES', false);
require($_SERVER['DOCUMENT_ROOT'].'wp-blog-header.php');
$message = '';
if ( is_user_logged_in() ):
wp_redirect('index.php');
exit();
else:
if ($_SERVER['REQUEST_METHOD'] == "POST"):
$login = $_POST['log'];
$password = $_POST['user_pass'];
if ( empty($login) || empty($password) ):
$message = 'Ошибка. Одно из полей оказалось пустым.';
exit();
endif;
$creds = array();
$creds['user_login'] = $login;
$creds['user_password'] = $password;
$creds['remember'] = true;
$user = wp_signon( $creds, false );
if ( is_wp_error($user) ) :
$message = $user->get_error_message();
else:
wp_redirect('index.php');
endif;
endif; # post
endif;
Листинг 3. Полный код loginhandler.php
Тут все просто и понятно. Мне даже описывать лень весь код, поэтому я просто опишу пару функций, которые могут вызвать непонятки.
is_user_logged_in ()
Проверяет залогинен пользователь или нет; возвращает true/false.
wp_signon ( $creds, $seccookie )
Осуществляет авторизацию пользователя в WordPress, проверяя на правильность и соответствие введенных данных с данными о пользователе в базе. Устанавливает куки, если все нормально.
is_wp_error ()
Проверяет полученный массив с данными пользователя на ошибки и возвращает сообщение с ошибкой, если таковое имеется.
wp_redirect ($where)
Осуществляет редирект.
Как и обещал, указываю еще несколько функций, который могут понадобиться при работе с логин-системой wp.
get_user_by_email ($user_name)
Получить данные о пользователе по email. Пример использования при проверке формуляра:
if (strpos($user_name, '@')): $user = get_user_by_email(trim($user_name)); if (empty($user)) echo 'Нет такого пользователя в базе.'; endif;
Листинг 4. Пример функции get_user_by_email ($user_name)
get_userdatabylogin ($_POST['username'])
Получить данные о пользователе по введенному логину.
wp_check_password ($_POST['password'], $hashpass, $user->ID)
Проверяет введенный в формуляре пароль с тем, который храниться в базе данных. Для использования этой функции необходимы пароль из базы и ID пользователя, которые можно получить с помощью get_userdatabylogin ().
Я такую схему часто реализую, только делаю, на мой взгляд, более расширено — создаю в теме login.php, в начале которой стоит комментарий:
/* Template Name: login */Так потом к страничке можно применить шаблон с этим именем.
Внутри — использую функции собственнописного плагина, который реализует проверки, подобные тем, что в самом ВП. Т.е. получается формочка, у которой вверху стоит только вызов обработчика (потому как я не понимаю, зачем ты используешь ajax в этом случае -здесь в любом случае нужна перезагрузка страницы, и использование js или тем паче Jquery просто-напросто лишнее).
Аналогично поступаю с страницами восстановления пароля, иногда с профилем и даже с публикацией постов — скажем, на ounce.su регятся разные пользователи и отправляют свои посты на модерацию, меняют свои профили и смотрят внутренний рейтинг авторов.
Ах да, одна вещь, которую ты пропустил в генерации формы — защита от удаленного входа. В самой форме надо вставить:
</code> </p><p>Это вставит инпут со скрытым значением в форму. </p><p><code>if ($_POST['_wpnonce'] != wp_create_nonce('login-user_'. $user_ID)) wp_die ("Fuck off hacker!");А вот этот кусок вставляем до проверки полей — если поля не будет, или хеш в этом поле не будет совпадать с тем, что должно будет, скрипт умрет.
(у тебя в новой теме почему-то рядом с именем комментатора в форме написано «не публикуется» :), и текст в текстарии слишком мелкий)
Да, про wp-nonce я забыл. С ajax удобнее и красивее, перегружать страницу как-то не айс.
Ну как тебе сказать про аякс... Вот, к примеру, при нажатии на кнопку «ответить» я жду, что форма комментария переместится к этому блоку без перезагрузки страницы — это, правда, не аякс, но js здесь к месту. Или, как в моем последнем проекте: раскрывая список архивных дел за неделю я вижу подсвеченные зеленым строчки тех контрактов, которые я еще не просматривал (новые), а аякс в этот момент помечает их как просмотренные.
Другой юзкейс, сейчас часто использующийся. Переход по однотипным спискам (или операции с ним вроде сортировок) делаются аяксом, когда мне из кафе, к примеру, приходится жлать и наслаждаться видом крутящегося прелоадера. В большинстве случаев совершенно неужная фича, которая ухудшает реакцию интерфейса, только если это не работа с часто обновляемым контентом (как, например, в Твиттере, где еще дополнительно экономится на запросах и объему передаваемых данных).
В нашем же текущем случае перегрузка страницы все равно необходима — при авторизации человек должен перейти на страницу дэшборда, тут нерационально подгружать хтмл, это понятно. Понятно, что ты хочешь красиво и быстро показывать ошибку, если пароль не совпадает — но в случае проекта, где в админк заходят только «избранные» это опять, как и в прошлом примере, будет лишним, — просто потому что страничка в любом случае обновится быстро, а количество ошибок ввода пароля исчезающе мало. Аякс здесь как дополнительный механизм — совершенно лишнее.
Вот в случае большого проекта, где люди заходят часто, я бы еще подумал. И то.
(понял, проблемы с жадностью регулярных выражений — парсер точно лох, да и мне надо будет исправиться и все-таки выпустить давно обещанное обновление плагина)
То ли я, то ли парсер что-то намудрил с кодом. Ты Типограф мой используешь (и если да, то какую версию?)?
Парсер лох. Использую типограф, вроде самый последний.
Собственно... а зачем она нужна??? чем не устраивает стандартная?
Попробовал сделать авторизацию через wp_signon. Возвращается нормальный user. Но после этого is_logged_id () возвращает false. То есть как бы пользователь и не в системе :(
а куда вставлять эти коды?