Хуки входа и регистрации в WordPress: как зарегистрировать своё действие
Регистрация действий (actions) в WordPress для хуков входа и регистрации
Действия (actions) в WordPress - это точки входа, позволяющие выполнить произвольный PHP-код в определённые моменты работы системы. Для хуков, связанных со входом и регистрацией пользователей, существуют стандартные действия, такие как user_register, wp_login, register_new_user и другие. Регистрация собственного обработчика (callback) выполняется с помощью функции add_action(), которая связывает имя действия с именем функции или замыканием.
Основной способ: использование add_action() для стандартного действия
Как зарегистрировать функцию, которая выполняется после успешной регистрации нового пользователя?
// functions.php вашей темы или в плагине
add_action( 'user_register', 'my_custom_registration_action', 10, 1 );
function my_custom_registration_action( $user_id ) {
// $user_id - ID только что созданного пользователя
$user = get_userdata( $user_id );
// Например, записать время регистрации в метаполе
update_user_meta( $user_id, 'registration_timestamp', time() );
// Отправить приветственное письмо
wp_mail( $user->user_email, 'Добро пожаловать!', 'Спасибо за регистрацию.' );
}
Action register php (регистрация действия (action) в php)
В этом примере используется приоритет 10 и один аргумент (user_id). Функция my_custom_registration_action будет вызвана сразу после создания записи пользователя в базе данных.
Как зарегистрировать обработчик для события входа пользователя?
add_action( 'wp_login', 'my_login_action', 10, 2 );
function my_login_action( $user_login, $user ) {
// $user_login - логин, $user - объект WP_User
// Записать время последнего входа
update_user_meta( $user->ID, 'last_login', current_time( 'mysql' ) );
}
Действие wp_login передаёт два аргумента: строку с именем пользователя и объект пользователя. Важно указать правильное число принимаемых аргументов в add_action().
Вариант 1: Использование анонимной функции (замыкания)
Как зарегистрировать действие без создания именованной функции, чтобы код был компактнее?
add_action( 'register_new_user', function( $user_id ) {
// Добавить пользователя в список рассылки
$email = get_userdata( $user_id )->user_email;
// условный вызов API внешнего сервиса
error_log( 'Новый пользователь зарегистрирован: ' . $email );
} );
Замыкания удобны для быстрых одноразовых действий, но их нельзя удалить через remove_action() без сохранения переменной.
Вариант 2: Регистрация действия с использованием метода класса
Как организовать код в объектно-ориентированном стиле для регистрации хуков?
class User_Logging {
public function __construct() {
add_action( 'wp_login', [ $this, 'log_login' ], 10, 2 );
add_action( 'user_register', [ $this, 'log_register' ] );
}
public function log_login( $user_login, $user ) {
// Логирование входа
$this->write_log( 'login', $user->ID );
}
public function log_register( $user_id ) {
$this->write_log( 'register', $user_id );
}
private function write_log( $type, $user_id ) {
global $wpdb;
$wpdb->insert( $wpdb->prefix . 'user_log', [
'user_id' => $user_id,
'action' => $type,
'time' => current_time( 'mysql' )
] );
}
}
new User_Logging();
Использование класса упрощает управление зависимостями и позволяет легко расширять функциональность.
Вариант 3: Создание собственного действия (custom action) и его регистрация
Как создать точку входа для других разработчиков и позволить им подключать свои функции?
// В вашем плагине или теме
function my_custom_user_action( $user_id ) {
// Ваш код
do_action( 'my_plugin_after_user_create', $user_id );
}
// Теперь другие разработчики могут зарегистрировать своё действие
add_action( 'my_plugin_after_user_create', 'another_function', 10, 1 );
Такой подход позволяет расширять функциональность без изменения основного кода. При создании собственных действий важно документировать передаваемые аргументы.
Вариант 4: Изменение приоритета и количества аргументов
Как сделать так, чтобы мой обработчик выполнился раньше или позже других, и как передать дополнительные данные?
// Высокий приоритет (выполнится раньше стандартных)
add_action( 'wp_authenticate', 'early_check', 1, 2 );
// Низкий приоритет (выполнится позже)
add_action( 'wp_authenticate', 'late_check', 99, 2 );
function early_check( $username, $password ) {
// Проверка ещё до аутентификации
}
Приоритет по умолчанию 10. Чем меньше число, тем раньше выполняется функция. Количество аргументов должно соответствовать тому, что передаёт действие. Ошибка в значении $accepted_args приведёт к тому, что функция получит меньше данных.
Типичные ошибки и способы их решения
Ошибка 1: Неправильное имя хука. Действие не срабатывает, потому что имя написано с опечаткой или не соответствует действительности. Решение: проверять список стандартных хуков в документации WordPress или использовать поиск по исходному коду.
Ошибка 2: Не указано количество аргументов. Функция принимает, например, один аргумент, а действие передаёт два. В результате второй аргумент игнорируется или возникает notice. Решение: всегда указывать $accepted_args в add_action().
Ошибка 3: Использование die() или exit() внутри хука, что может прервать нормальный процесс регистрации или входа. Решение: вместо прерывания использовать возврат ошибки или исключение, если это действительно необходимо, и только после основного действия.
Ошибка 4: Попытка зарегистрировать действие внутри условного блока, который не выполняется. Например, вызов add_action() внутри if ( is_admin() ) может пропустить хуки на фронтенде. Решение: размещать регистрацию в общем коде, который загружается всегда.
Ошибка 5: Глобальные переменные не объявлены. При использовании global $wpdb или $post внутри хука нужно убедиться, что они доступны в момент вызова. Решение: явно объявлять глобальные переменные внутри функции.
Расширенные примеры регистрации действий для входа и регистрации
Пример 1: Запись IP-адреса при входе пользователя
Цель: сохранять IP-адрес, с которого был выполнен вход, для целей безопасности или статистики.
add_action( 'wp_login', 'record_login_ip', 10, 2 );
function record_login_ip( $user_login, $user ) {
$ip = $_SERVER['REMOTE_ADDR'];
update_user_meta( $user->ID, 'last_login_ip', $ip );
}
После входа в метаполе last_login_ip будет записан IP. Это позволяет отслеживать необычные попытки входа.
// При входе пользователя 'admin' с IP 192.168.1.1 // В таблице wp_usermeta появится запись: // user_id: 1, meta_key: 'last_login_ip', meta_value: '192.168.1.1'
Пример 2: Отправка приветственного письма с индивидуальным содержимым
Цель: после регистрации отправить письмо с логином и ссылкой для подтверждения email.
add_action( 'user_register', 'send_welcome_email', 10, 1 );
function send_welcome_email( $user_id ) {
$user = get_userdata( $user_id );
$subject = 'Добро пожаловать, ' . $user->display_name;
$message = 'Вы зарегистрировались на нашем сайте. Ваш логин: ' . $user->user_login . "\n";
$message .= 'Для подтверждения перейдите по ссылке: ' . home_url( '/confirm-email?key=' . md5( $user->user_email ) );
wp_mail( $user->user_email, $subject, $message );
}
Здесь важно, чтобы письмо не попало в спам. Рекомендуется использовать HTML-формат и правильные заголовки.
Пример 3: Добавление пользователя в группу подписчиков после регистрации
Цель: автоматически добавлять всех новых пользователей в определённую роль (например, 'subscriber'), если регистрация произошла через форму на странице 'pro'.
add_action( 'register_new_user', 'set_user_role_based_on_referrer', 10, 1 );
function set_user_role_based_on_referrer( $user_id ) {
$referrer = $_POST['_wp_http_referer'] ?? '';
if ( strpos( $referrer, 'pro' ) !== false ) {
$user = new WP_User( $user_id );
$user->set_role( 'pro_subscriber' );
}
}
Однако такая логика может быть небезопасной: рекомендуется проверять nonce и другие данные формы.
Пример 4: Использование хука wp_authenticate_pre для дополнительной проверки
Цель: заблокировать вход для определённых пользователей до аутентификации.
add_action( 'wp_authenticate_pre', 'check_banned_users', 10, 2 );
function check_banned_users( $username, $password ) {
// Получаем пользователя по логину
$user = get_user_by( 'login', $username );
if ( $user && get_user_meta( $user->ID, 'banned', true ) ) {
// Останавливаем процесс входа, возвращая ошибку
wp_die( 'Ваш аккаунт заблокирован.' );
}
}
Обратите внимание: wp_die() здесь уместно, так как это блокирующая проверка до основного потока аутентификации.
Пример 5: Создание собственного действия и его вызов с произвольными аргументами
Цель: дать возможность другим плагинам реагировать на пользовательское событие, например, когда пользователь завершает профиль.
// В вашем плагине
function do_after_profile_complete( $user_id, $profile_data ) {
// Ваш код обработки
do_action( 'my_plugin_profile_completed', $user_id, $profile_data );
}
// В другом плагине регистрируем обработчик
add_action( 'my_plugin_profile_completed', 'notify_admin_about_profile', 10, 2 );
function notify_admin_about_profile( $user_id, $data ) {
$admin_email = get_option( 'admin_email' );
wp_mail( $admin_email, 'Профиль завершён', 'Пользователь ID ' . $user_id . ' завершил профиль.' );
}
При вызове do_action() передаются все необходимые аргументы, которые могут быть использованы зарегистрированными функциями.
Пример 6: Использование анонимной функции с доступом к внешним переменным (use)
Цель: передать в замыкание дополнительные данные, определённые в контексте.
$plugin_option = get_option( 'my_plugin_log_level' );
add_action( 'wp_login', function( $user_login, $user ) use ( $plugin_option ) {
if ( $plugin_option === 'debug' ) {
error_log( 'Вход пользователя: ' . $user_login );
}
}, 10, 2 );
Конструкция use позволяет замкнуть переменную из области видимости. Однако будьте осторожны: значение фиксируется при регистрации, а не при выполнении.