Кастомная аутентификация пользователей WordPress с PHP
Основные методы логина WordPress через PHP
Как создать кастомную страницу входа с помощью wp_login_form() и обработки отправки?
Стандартная страница wp-login.php обладает ограниченными возможностями кастомизации. Для создания собственной страницы входа используется функция wp_login_form(), которая выводит готовую форму. Обработка данных выполняется через фильтр login_form_ или перехват отправки на wp_ajax_login. Ниже приведен пример реализации страницы входа с проверкой и редиректом.
// Создаем шорткод для вывода формы
add_shortcode('custom_login_form', 'custom_login_form_shortcode');
function custom_login_form_shortcode() {
global $wp;
$redirect = home_url();
if (isset($_GET['redirect_to'])) {
$redirect = esc_url($_GET['redirect_to']);
}
$args = array(
'redirect' => $redirect,
'form_id' => 'custom-login-form',
'label_username' => __('Имя пользователя или email'),
'label_password' => __('Пароль'),
'label_log_in' => __('Войти'),
'remember' => true,
);
ob_start();
wp_login_form($args);
return ob_get_clean();
}Шорткод [custom_login_form] можно разместить на любой странице. Для обработки отправки формы используется крюк init:
add_action('init', 'handle_custom_login');
function handle_custom_login() {
if (isset($_POST['log']) && isset($_POST['pwd'])) {
$creds = array(
'user_login' => sanitize_user($_POST['log']),
'user_password' => $_POST['pwd'],
'remember' => isset($_POST['rememberme'])
);
$user = wp_signon($creds, is_ssl());
if (is_wp_error($user)) {
// Выводим ошибку
$_SESSION['login_error'] = $user->get_error_message();
} else {
wp_redirect($_POST['redirect_to'] ?? home_url());
exit;
}
}
}Типичные ошибки: сессия не запускается – необходимо вызвать session_start() в начале темы; не устанавливается cookie – проверьте is_ssl() и константу FORCE_SSL_LOGIN; редирект не срабатывает – используйте exit после wp_redirect.
Как выполнить проверку учетных данных без стандартной формы?
Для аутентификации в произвольном месте используется функция wp_authenticate(). Она принимает логин и пароль, возвращает объект пользователя или ошибку WP_Error.
$user = wp_authenticate('username', 'password');
if (is_wp_error($user)) {
// Ошибка: неверный логин или пароль
$error_code = $user->get_error_code();
} else {
// Успешный вход
wp_set_current_user($user->ID);
wp_set_auth_cookie($user->ID);
do_action('wp_login', $user->user_login, $user);
}Проблемы: вызов wp_set_auth_cookie() без предварительной проверки nonce приводит к уязвимостям CSRF; требуется установить wp_set_current_user() перед вызовом do_action('wp_login').
Как перенаправить посетителей с wp-login.php на кастомную страницу?
Для блокировки прямого доступа к стандартной странице входа используется фильтр login_url и редирект с init на основе шаблона.
add_action('init', 'redirect_login_page');
function redirect_login_page() {
global $pagenow;
if ($pagenow === 'wp-login.php' && !isset($_GET['action'])) {
wp_redirect(home_url('/login/'));
exit;
}
}Ошибка: бесконечный редирект, если кастомная страница также использует wp-login.php в обработчике – проверяйте, что редирект происходит только на страницу без wp-login.php.
Как расширить стандартную форму входа дополнительными полями?
С помощью фильтров login_form, login_form_middle, authenticate можно добавить, например, капчу или поле выбора роли.
add_filter('login_form_middle', 'add_extra_login_field');
function add_extra_login_field() {
return '<label for="extra_field">Дополнительное поле:</label>
<input type="text" name="extra_field" id="extra_field" />';
}
add_filter('authenticate', 'validate_extra_field', 10, 3);
function validate_extra_field($user, $username, $password) {
if (empty($_POST['extra_field'])) {
return new WP_Error('no_extra', __('Заполните дополнительное поле'));
}
return $user;
}Проблема: фильтр authenticate срабатывает только если $user еще не является объектом WP_User – проверяйте приоритет и возвращайте объект пользователя, если проверка пройдена.
Как вывести собственные сообщения об ошибках при входе?
Ошибки по умолчанию выводятся через login_errors. Для замены используйте фильтр login_errors или перехватывайте сообщения в кастомном обработчике.
add_filter('login_errors', 'custom_login_error_message');
function custom_login_error_message($error) {
global $errors;
if (isset($errors->errors['invalid_username'])) {
$error = 'Пользователь с таким именем не найден.';
}
return $error;
}Ошибка: переменная $errors может быть не определена – проверяйте isset.
Расширенные примеры логина в WordPress
1. Кастомный REST API endpoint для аутентификации
Пример создания эндпоинта /wp-json/custom/v1/login, который возвращает токен (используется в SPA).
add_action('rest_api_init', function () {
register_rest_route('custom/v1', '/login', array(
'methods' => 'POST',
'callback' => 'custom_rest_login',
));
});
function custom_rest_login($request) {
$params = $request->get_json_params();
$username = sanitize_user($params['username']);
$password = $params['password'];
$user = wp_authenticate($username, $password);
if (is_wp_error($user)) {
return new WP_Error('login_failed', $user->get_error_message(), array('status' => 401));
}
$token = wp_generate_password(64, false); // упрощённо, лучше использовать JWT
update_user_meta($user->ID, 'api_token', $token);
return array(
'token' => $token,
'user_id' => $user->ID,
);
}// Пример запроса:
// POST /wp-json/custom/v1/login
// Body: {"username":"admin","password":"12345"}
// Ответ: {"token":"abc...","user_id":1}2. Использование wp_signon() с произвольными данными
Функция wp_signon() объединяет проверку и установку сессии. Ниже пример входа на основе email (стандартно логин – username).
$email = 'user@example.com';
$user = get_user_by('email', $email);
if ($user) {
$creds = array(
'user_login' => $user->user_login,
'user_password' => 'password',
'remember' => true
);
$signed_user = wp_signon($creds, false);
if (!is_wp_error($signed_user)) {
wp_redirect(home_url());
exit;
}
}// После успешного входа пользователь оказывается на главной странице.
3. Полноценная страница входа с выводом ошибок в шаблоне
Пример использования переменной сессии для хранения ошибки и её вывода.
// В functions.php
add_action('init', 'handle_login_form');
if (!session_id()) session_start();
function handle_login_form() {
if (isset($_POST['custom_login'])) {
$login = sanitize_user($_POST['log']);
$password = $_POST['pwd'];
$creds = array(
'user_login' => $login,
'user_password' => $password,
'remember' => isset($_POST['rememberme'])
);
$user = wp_signon($creds, is_ssl());
if (is_wp_error($user)) {
$_SESSION['login_error'] = $user->get_error_message();
wp_redirect(add_query_arg('login', 'failed', wp_get_referer()));
exit;
} else {
wp_redirect(home_url());
exit;
}
}
}
// В шаблоне страницы входа:
if (isset($_SESSION['login_error'])) {
echo '<div class="error">' . esc_html($_SESSION['login_error']) . '</div>';
unset($_SESSION['login_error']);
}// После неудачной попытки выводится сообщение об ошибке, после успеха – редирект.
4. Интеграция Google reCAPTCHA с формой входа
Добавление проверки reCAPTCHA через фильтр login_form и authenticate.
add_action('login_form', 'add_recaptcha_to_login');
function add_recaptcha_to_login() {
$site_key = 'YOUR_SITE_KEY';
echo '<div class="g-recaptcha" data-sitekey="' . esc_attr($site_key) . '"></div>';
echo '<script src="https://www.google.com/recaptcha/api.js" async defer></script>';
}
add_filter('authenticate', 'verify_recaptcha', 10, 3);
function verify_recaptcha($user, $username, $password) {
if (isset($_POST['g-recaptcha-response'])) {
$response = wp_remote_post('https://www.google.com/recaptcha/api/siteverify', array(
'body' => array(
'secret' => 'YOUR_SECRET_KEY',
'response' => $_POST['g-recaptcha-response']
)
));
$result = json_decode(wp_remote_retrieve_body($response));
if (!$result->success) {
return new WP_Error('captcha_failed', 'Проверка капчи не пройдена.');
}
}
return $user;
}// Если капча не пройдена – ошибка, иначе обычная аутентификация.