Как программно изменить имя пользователя (user_login)?
Как указано в заголовке, как программно изменить логин пользователя?
Я хотел использовать функцию wp_insert_user, но оказалось, что при обновлении текущего пользователя она не меняет его имя пользователя. Следует ли использовать $wpdb->update для этого? Если да, как будет выглядеть код для изменения имени пользователя? Какие последствия будет иметь изменение логина пользователя, учитывая, что API WordPress не позволяет менять имена пользователей?
Я был уверен, что функция wp_update_user() должна это делать.
Она даже принимает user_login как параметр, но похоже, что игнорирует его, когда вы его устанавливаете.
Так что этот код выглядит нормально, но он не работает так, как хотелось бы :( :
wp_update_user(
['ID' => $user_id, 'user_login' => $new_login]
);
Вам нужно выполнить пользовательский SQL-запрос для обновления user_login:
global $wpdb;
$wpdb->update(
$wpdb->users,
['user_login' => $new_user_login],
['ID' => $user_id]
);
Это работает нормально, и я не думаю, что это имеет какие-то серьезные последствия, потому что WordPress использует ID пользователей для привязки записей/комментариев (и так далее) к пользователю.
Единственная проблема, о которой я могу подумать, это то, что если этот пользователь в данный момент авторизован, он будет разлогинен после изменения user_login.
На самом деле нет, ознакомьтесь с примечаниями к этой функции (а также с кодом): Обратите внимание, что мы не можем изменять имена пользователей через эту функцию, более того, имена пользователей нельзя изменить и из админ-панели, поскольку WordPress не позволяет обновлять имена пользователей.
Mateusz Hajdziony
Спасибо, это отлично работает! Хотя беспокоиться о вошедших пользователях не стоит, так как я разрешаю смену имени пользователя только для вышедших из системы (активация аккаунта по электронной почте).
Mateusz Hajdziony
@pogoking Возможно, вам стоит учесть, что постоянные ссылки пользователей или авторов могут перестать работать после разрешения смены имен пользователей, если включены ЧПУ, поэтому вам может потребоваться принять меры для компенсации этого.
Ahmad M
@AhmadM Спасибо, Ахмад, но как я уже говорил ранее - пользователи до активации аккаунта не будут отображаться нигде, так что проблема с постоянными ссылками отсутствует. Но спасибо за предупреждение!
Mateusz Hajdziony
@Mauro Ну, если ты запускаешь этот код внутри функции, тогда да - конечно. Тебе также нужно объявить $user_id и $new_login, но это очевидно и не связано с WP, верно?
Krzysiek Dróżdż
Старый пост, но я сам рассматриваю эту возможность. Стоит проверить, нет ли другого пользователя с таким же user_login на вашем сайте, так как форма входа использует это значение для поиска аккаунтов и проверки хэшей паролей.
haxxxton
@haxxxton У меня была та же мысль, ! username_exists( sanitize_user( $new_user_login ) ); сделает именно это.
amarinediary
Я бы предложил добавить либо update_user_caches(get_user_by('id', $user_id)), либо clean_user_cache($user_id) после этого обновления, если вы используете wp_object_cache. Я на собственном опыте убедился, что прямое изменение записей пользователей в WP может привести к очень неожиданному поведению.
Dan B
В дополнение к ответу Krzysiek Dróżdż.
Если вы не хотите, чтобы пользователи выходили из системы после изменения user_login, вам нужно выполнить следующее, чтобы пользователь оставался в системе с новыми данными:
clean_user_cache($user->ID);
wp_clear_auth_cookie();
wp_set_current_user($user->ID);
wp_set_auth_cookie($user->ID, true);
update_user_caches($user);
Вы должны использовать фильтр для изменения $data при обновлении пользователя, нельзя использовать действие, которое обычно применяется для хука при обновлении пользователя.
Также необходимо перенести несколько мер безопасности и проверок, которые WordPress выполняет в своём коде, в вашу новую функцию.
Что можно сделать:
- Подключиться к фильтру
wp_pre_insert_user_data. Убедитесь, что делаете это только при наличии соответствующих прав:add_filter( 'wp_pre_insert_user_data', 'prefix_change_user_login', 10, 4 ); - Теперь создайте функцию
prefix_change_user_login, где вы получите$data,user_loginиз$_POSTи пропустите его через ряд валидаций и санитаций (подробнее см. https://github.com/WordPress/wordpress-develop/blob/bb27ffce6c3b10738008f9a054782945a0744960/src/wp-includes/user.php#L2076-L2498) - Кроме того, вам нужно разрешить редактирование поля логина пользователя в экране редактирования пользователя в админке WordPress или передать это значение в ваш код другим способом.
Пример такой функции:
/**
* Обновление логина пользователя
*
* @since x.x.x
* @param array $data {
* Значения и ключи для пользователя.
*
* @type string $user_login Логин пользователя. Включается только если $update == false
* @type string $user_pass Пароль пользователя.
* @type string $user_email Email пользователя.
* @type string $user_url URL пользователя.
* @type string $user_nicename Красивое имя пользователя. По умолчанию — URL-безопасная версия логина.
* @type string $display_name Отображаемое имя пользователя.
* @type string $user_registered MySQL-метка времени, описывающая момент регистрации пользователя. По умолчанию —
* текущая UTC-метка времени.
* }
* @param bool $update Обновляется ли пользователь, а не создаётся.
* @param int|null $user_id ID пользователя для обновления или NULL, если пользователь создаётся.
* @param array $userdata Необработанный массив данных, переданный в wp_insert_user().
*/
function prefix_change_user_login( $data, $update, $user_id, $userdata ){
// НЕ ЗАБУДЬТЕ ДОБАВИТЬ ПРОВЕРКУ NONCE И REFERRER ЗДЕСЬ!!!!
$sanitized_user_login = sanitize_user( wp_unslash( $_POST['user_login'] ), true ); // В нашем случае получаем новый логин из значения формы в админке. Если у вас другой случай использования — адаптируйте!
/**
* Фильтрует имя пользователя после его санитарии.
*
* Этот фильтр вызывается перед созданием или обновлением пользователя.
*
* @since 2.0.3
*
* @param string $sanitized_user_login Имя пользователя после санитарии.
*/
$pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login );
$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
// Удаляем любые непечатаемые символы из строки логина, чтобы проверить, не осталась ли она пустой.
$user_login = trim( $pre_user_login );
if ( empty( $user_login )
|| mb_strlen( $user_login ) > 60
|| username_exists( $user_login )
|| in_array( strtolower( $user_login ), array_map( 'strtolower', $illegal_logins ), true )
) {
return $data;
}
$data['user_login'] = $user_login;
$user_nicename = sanitize_title( mb_substr( $user_login, 0, 50 ) ); // Кто знает, что курили разработчики WP, когда решили сделать nicename на 10 символов короче логина?
global $wpdb;
$user_nicename_check = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1", $user_nicename, $user_login ) );
if ( $user_nicename_check ) {
$suffix = 2;
while ( $user_nicename_check ) {
// user_nicename позволяет 50 символов. Вычитаем один для дефиса плюс длину суффикса.
$base_length = 49 - mb_strlen( $suffix );
$alt_user_nicename = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix";
$user_nicename_check = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1", $alt_user_nicename, $user_login ) );
$suffix++;
}
$user_nicename = $alt_user_nicename;
}
$data['user_nicename'] = $user_nicename;
return $data;
}
Теперь это позволит вам обновлять логин пользователя, а также обновлять красивое имя пользователя (используемое, например, в архивах).
Конечно, это всё ещё требует "включения" редактирования в области админки WordPress, но это не должно быть слишком сложно.
Обратите внимание, что если в приведённом выше коде произойдёт ошибка (логин уже существует и т.д.), НИКАКАЯ ошибка не отобразится — вместо этого пользователь просто обновится, вернувшись к предыдущему значению.
Также учтите, что хотя этот код протестирован, вы используете его на свой страх и риск, и у WordPress ЕСТЬ ПРИЧИНЫ не разрешать обновление логина пользователя.