Кастомная аутентификация пользователей WordPress с PHP

Раздел: CMS и фреймворки -> Разработка под WordPress

Основные методы логина 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;
}
// Если капча не пройдена – ошибка, иначе обычная аутентификация.

Логин WordPress PHP - comments

En
Wp login php (php)