Форма авторизации в 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 ().

Другие полезняшки для WordPress:

  • Я такую схему часто реализую, только делаю, на мой взгляд, более расширено — создаю в теме 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. То есть как бы пользователь и не в системе :(

  • а куда вставлять эти коды?

Ваш комментарий

XHTML: вы можете воспользоваться следующими тагами: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>