Как запретить доступ к wp-admin для определенных ролей пользователей?
Я пытался использовать плагин Front End Users, но он конфликтует с чем-то, так как блокирует доступ к некоторым страницам на фронтенде. Поэтому мне нужно вручную настроить так, чтобы любой пользователь, кроме двух определенных имен пользователей (или ролей), не мог получить доступ к wp-admin.

Плагин
По сути, это просто проверка прав пользователя с последующим редиректом через вызов exit. Затем происходит перенаправление на сайт, откуда пришел запрос.
<?php
! defined( 'ABSPATH' ) AND exit;
/* Plugin Name: (#66093) »kaiser« Запрет доступа к админке для определенных ролей */
function wpse66093_no_admin_access()
{
// Не выполнять, если пользователь вошел в систему и пытается выйти
// Возможно, потребуется одна или две дополнительные проверки.
// Особенно если у вас настроены кастомные правила и маршруты для входа/выхода/сброса пароля и т.д.
if (
! is_admin()
|| (
is_user_logged_in()
&& isset( $GLOBALS['pagenow'] ) AND 'wp-login.php' === $GLOBALS['pagenow']
)
) {
return;
}
$redirect = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : home_url( '/' );
if (
current_user_can( 'CAPABILITY_NAME_HERE' )
OR current_user_can( 'CAPABILITY_NAME_HERE' )
)
exit( wp_redirect( $redirect ) );
}
add_action( 'admin_init', 'wpse66093_no_admin_access', 100 );
Учтите, что это будет работать только со стандартными настройками (см. комментарии в коде). Кастомная логика входа, выхода, регистрации или сброса пароля может нарушить работу плагина.
Роли vs. Права: Поскольку названия ролей могут меняться, а роли — это просто группы прав, лучше проверять конкретные права, а не названия ролей. Список встроенных ролей и прав можно найти здесь. Просто посмотрите, какие права наиболее ограничены, и найдите подходящее. Затем укажите его в коде выше. Так проще поддерживать код, если название роли изменится. Да, вы можете использовать и название роли, что будет работать в WordPress, но это может привести к трудноуловимым багам при изменении названия роли.
Примечание: Не думайте о ролях в иерархическом ключе. Представьте бухгалтера, чей email вы вводите в SaaS-системе для получения счетов. Большинство разработчиков не имеют доступа к платежным данным, а бухгалтер — к настройкам деплоя или безопасности. У них разные роли с одинаково «высокими» правами, но для совершенно разных частей системы. Держите этот пример в голове, когда пишете проверки прав или добавляете кастомные права в систему.

Либо где-нибудь в вашем functions.php, либо в папке плагина или mu-plugins. Поскольку это не связано с отображением контента, imho это должно быть в плагине, отсюда и заголовок плагина. Это имеет преимущество, что функциональность не теряется при смене темы. Просто измените названия ролей пользователей, загрузите и готово.

Это не работает. Я изменил названия ролей пользователей на свои две роли, которые могут получить доступ. Затем я изменил его на capability, например Add users
, но я всё ещё могу получить доступ к бэкенду под другой ролью пользователя

@Nicola Существует огромная разница между меткой в интерфейсе (например: "Добавить пользователей") и реальной Ролью или Возможностью - в вашем случае add_users
.

Хорошо, спасибо, я попробовал приведённый выше код с add_users вместо этого, и он всё равно не работает... если я вхожу как пользователь без этой возможности, я всё равно могу перейти в wp-admin

@Nicola Вы ознакомились со ссылкой о Ролях и Возможностях ↑ в комментарии выше? Пожалуйста, убедитесь, что пользователь действительно не имеет этой возможности.

Эй, у них точно нет такой возможности. Я просто добавил код в свой файл functions.php, так как не был уверен, как сделать это плагином, который WordPress распознает. Также у меня была ошибка, где $_SERVER['HTTP_REFERER']
был неопределенным индексом, поэтому я добавил проверку if isset перед ним.

А, понятно. Теперь мы знаем, в чем проблема: я обновил ответ, но нужно добавить это как плагин. Это плагин, он будет распознан. Я просто не добавил полный заголовок (что необязательно). Вы также можете запустить его как mu-плагин (почитайте в codex об этом). Лучше оставить его как плагин, чтобы он не потерялся при смене темы.

Хорошо, можешь отредактировать его с использованием if isset
, так как снова срабатывает ошибка неопределенного индекса 'HTTP_REFERER', и я не уверен в твоей логике, чтобы правильно его отредактировать.

эй, это круто, я просто сделал перенаправление на главную страницу сайта. Теперь всё работает, спасибо!

Снова здравствуйте, у меня есть ещё одна задача. У меня есть плагин, который позволяет пользователю обновлять свою фотографию прямо из интерфейса. Этот плагин выполняет некоторые AJAX-операции на сервере для этого.
В приведённом выше коде я предполагаю, что нужно проверить, находимся ли мы на этой странице. Однако, так как мы находимся в директории плагина, он не может определить текущую страницу через функции WordPress, поэтому я использовал $page = array_shift( explode( '?', $_SERVER['REQUEST_URI'] ) );
, а затем попытался изменить код выше, добавив условие if ( current_user_can( 'add_users' ) || $page=="/your-profile/"){
, но это не сработало.

@Nicola Пожалуйста, всегда добавляйте такую информацию в первоначальный вопрос как правку, а не в комментарий здесь. Во-вторых, пожалуйста, задавайте новый вопрос, когда тема меняется или расширяется. Спасибо.

Всё в порядке, я разобрался, добавив die($page) и понял, что плагин вызывается только при нажатии на редактирование профиля, в этот момент $page="/wp-admin/admin-ajax.php"
. Теперь всё исправлено.

WordPress, вероятно, начнёт вызывать _doing_it_wrong()
при проверке имени роли как capability в current_user_can()
. См. 38653

Хорошо, однако пользователи не могут выйти из системы из-за этого действия.

Недавно пересмотрел этот ответ, так как он давно не обновлялся. Сейчас 2021 год.
Принятый ответ проверяет, является ли текущая страница страницей wp-login.php
ИЛИ административной страницей ВО ВРЕМЯ использования хука admin_init
, что бессмысленно.
admin_init
срабатывает при инициализации административного экрана или скрипта. Он НЕ работает только на пользовательских административных экранах. Он также запускается на admin-ajax.php
и admin-post.php
.
Ни в коем случае он не сработает на wp-login.php
, так как это НЕ административный экран. Хотя он действительно сработает при AJAX-запросе, поэтому этот случай нужно обрабатывать. wp_doing_ajax()
определяет, является ли текущий запрос AJAX-запросом WordPress.
В следующем примере я использую пользовательскую способность delete_posts
, чтобы разрешить доступ к бэкенду WordPress для ролей admin
, editor
и author
. Для более строгого подхода обратитесь к Таблице возможностей и ролей.
Напоминание о стандартных ролях WordPress (Сводка ролей):
супер администратор
→
администратор→
редактор→
автор→
участник→
подписчик.
В однопользовательской установке WordPress администраторы фактически являются супер администраторами.
Я выбрал использование wp_die()
вместо простого перенаправления пользователей. wp_die()
предоставляет своего рода пользовательское сопровождение, так как останавливает выполнение WordPress и отображает HTML-страницу с сообщением об ошибке. Такой же подход можно реализовать с перенаправлением пользователей на страницу 404. Любое объяснение ситуации лучше, чем слепое перенаправление на домашнюю страницу.
add_action( 'admin_init', 'restrict_wpadmin_access' );
if ( ! function_exists( 'restrict_wpadmin_access' ) ) {
function restrict_wpadmin_access() {
if ( wp_doing_ajax() || current_user_can( 'delete_posts' ) ) {
return;
} else {
header( 'Refresh: 2; ' . esc_url( home_url() ) );
$args = array(
'back_link' => true,
);
wp_die( 'Доступ запрещён.', 'Ошибка', $args );
};
};
};
Чтобы предотвратить стандартное перенаправление на wp-admin.php
после входа, я использую фильтр хука login_redirect
, который фильтрует URL перенаправления при входе. Я перенаправляю пользователей на их собственную страницу профиля, используя get_author_posts_url()
, но вы можете легко перенаправить на любую страницу. Вы также можете условно перенаправлять в зависимости от роли пользователя (например, администраторов на административную страницу, остальных на профиль), всё объяснено в разделе примеров на странице CODEX.
add_filter( 'login_redirect', 'redirect_user_to_profile_on_login', 10, 3 );
if ( ! function_exists( 'redirect_user_to_profile_on_login' ) ) {
function redirect_user_to_profile_on_login( $redirect_to, $requested_redirect_to, $user ) {
if ( $user && is_object( $user ) && is_a( $user, 'WP_User' ) ) {
$redirect_to = esc_url( get_author_posts_url( $user->ID ) );
};
return $redirect_to;
};
};

Принятый ответ упоминает Роль пользователя, но фактически использует функцию для Возможности пользователя.
Вот решение для Ролей пользователя:
function wpse66094_no_admin_access() {
$redirect = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : home_url( '/' );
global $current_user;
$user_roles = $current_user->roles;
$user_role = array_shift($user_roles);
if($user_role === 'YOUR_USER_ROLE_HERE'){
exit( wp_redirect( $redirect ) );
}
}
add_action( 'admin_init', 'wpse66094_no_admin_access', 100 );

Вы должны проверять возможности (capabilities), а не роли. Как указано на странице CODEX функции current_user_can()
: "Хотя проверка конкретных ролей вместо возможностей частично поддерживается, такая практика не рекомендуется, так как может давать ненадёжные результаты.
@see https://developer.wordpress.org/reference/functions/current_user_can/#description

На основе ответа, предоставленного @kaiser (спасибо, кстати), вот мой рабочий код, на случай, если кому-то он понадобится. Код размещается в файле functions.php
.
Условие таково: если пользователь не может manage_options
или edit_posts
.
function wpse66093_no_admin_access() {
$redirect = home_url( '/' );
if ( ! ( current_user_can( 'manage_options' ) || current_user_can( 'edit_posts' ) ) )
exit( wp_redirect( $redirect ) );
}
add_action( 'admin_init', 'wpse66093_no_admin_access', 100 );

Используя ответ @kaiser, я обнаружил, что вам нужно использовать хук admin_menu вместо admin_init, так как он срабатывает до проверки !user_can_access_admin_page() в wp-admin/includes/menu.php. В противном случае, если пользователь не имеет доступа 'read' к панели управления, он просто получит страницу с сообщением 'У вас недостаточно прав для доступа к этой странице.' вместо перенаправления.

Если удалить возможность read
у роли, пользователь не сможет получить доступ к консоли. Он увидит следующую ошибку:
У вас недостаточно прав для доступа к этой странице админки.
Причина: текущий пользователь не имеет возможности "read", которая требуется для доступа к пункту меню "Консоль".
Ссылка: https://codex.wordpress.org/Roles_and_Capabilities#read
