Если текущий пользователь является администратором или редактором
Как я могу проверить, является ли текущий авторизованный пользователь администратором или редактором?
Я знаю, как сделать каждую проверку по отдельности:
<?php if(current_user_can('editor')) { ?>
<!-- Контент для редакторов -->
<?php } ?>
<?php if(current_user_can('administrator')) { ?>
<!-- Контент для администраторов -->
<?php } ?>
Но как мне объединить эти проверки? То есть, чтобы проверить, является ли пользователь администратором или редактором?

Первый ответ, не связанный с WordPress, потому что это просто PHP: Используйте логический оператор "ИЛИ":
<?php if( current_user_can('editor') || current_user_can('administrator') ) { ?>
// Здесь код для администраторов или редакторов
<?php } ?>
Если вы хотите проверить более двух ролей, вы можете проверить, находятся ли роли текущего пользователя внутри массива ролей, что-то вроде:
$user = wp_get_current_user();
$allowed_roles = array('editor', 'administrator', 'author');
<?php if( array_intersect($allowed_roles, $user->roles ) ) { ?>
// Здесь код для разрешенных ролей
<?php } ?>
Однако, current_user_can
может использоваться не только с названиями ролей пользователей, но и с возможностями (capabilities).
Таким образом, поскольку и редакторы, и администраторы могут редактировать страницы, ваша задача может быть упрощена проверкой этих возможностей:
<?php if( current_user_can('edit_others_pages') ) { ?>
// Здесь код для ролей пользователей, которые могут редактировать страницы: редакторы и администраторы
<?php } ?>
Посмотрите здесь для получения дополнительной информации о возможностях.

@RobBenz нет, ни в одном из случаев. Потому что current_user_can()
всегда возвращает false, если пользователь не авторизован, а wp_get_current_user()
вернет пользователя без какой-либо роли, если пользователь не авторизован, поэтому array_intersect()
всегда будет false.

В PHPDoc функции current_user_can()
мы можем увидеть строку "Хотя проверка определенных ролей вместо возможностей частично поддерживается, эта практика не рекомендуется, так как может привести к ненадежным результатам". Поэтому я думаю, что лучше избегать использования ролей при проверке возможностей пользователя :-)

Когда я использую метод array_intersect
, я получаю PHP-предупреждение в журнале ошибок сервера, говорящее array_intersect(): Argument #2 is not an array
. Это происходит потому, что у пользователя(ей) есть только одна Роль?

@Garconis обычно это должен быть массив. По какой-то причине похоже, что у вас это не массив. array_intersect($allowed_roles, (array)$user->roles )
будет работать без проблем.

Я бы посоветовал проверять не роли, а возможности. Легче удалить или добавить возможность набору ролей... это более явно. Например, current_user_can('edit_orderform')
... возможно, менеджер по продажам должен ТОЛЬКО иметь возможность редактировать форму заказа... но не иметь прав на добавление контента. Явное предоставление такой возможности - это более четкая структура разрешений, чем роль пользователя. В крупных организациях люди выполняют несколько функций. У вас могут быть подписчики, имеющие больший доступ, чем просто чтение.

Во-первых, current_user_can()
не следует использовать для проверки роли пользователя - его следует использовать для проверки наличия у пользователя определенного права доступа.
Во-вторых, вместо того, чтобы беспокоиться о роли пользователя, а сосредоточиться на правах доступа, вам не нужно заботиться о решении проблем, подобных той, что была задана в исходном вопросе (проверка, является ли пользователь администратором ИЛИ редактором). Вместо этого, если current_user_can()
использовалась бы по назначению, то есть для проверки прав доступа пользователя, а не его роли, вам не потребовалась бы условная проверка с использованием "или" (||). Например:
if ( current_user_can( 'edit_pages' ) ) { ...
edit_pages - это право доступа, которое есть у ролей администратора и редактора, но отсутствует у более низких ролей, таких как авторы. Именно так и предполагалось использовать current_user_can()
.

Обратите внимание: Опытные WP разработчики согласны с этим ответом. Следует по возможности избегать проверки ролей и использовать возможности (capabilities). В настоящее время я работаю над проектом с несколькими ролями, которые имеют только возможность 'read'. Для меня единственное решение - это проверка ролей. Извините, я не могу найти ссылку, это было открытое обсуждение на GitHub WordPress.

На мой взгляд, это должен быть принятый ответ. current_user_can
обычно следует использовать для проверки возможностей (capabilities), а не ролей.

+1 к этому, избегайте проверки ролей через current_user_can()
. Если вы хотите проверить роли по ключу, тогда выполняйте проверку роли вместо проверки возможностей :)

Какая тогда правильная функция для явной и безопасной проверки ролей пользователей? Кажется, её довольно сложно найти (если она существует). @Bjorn

@Viktor Borítás На этой странице есть несколько правильных решений. Но используйте их только если current_user_can()
не подходит. Кроме того, мой комментарий больше касается безопасности. Например, если вы хотите ограничить контент для определенных пользователей, в большинстве случаев достаточно проверки возможностей для этой задачи.

Предпочтительнее использовать возможности (capabilities) "для защиты" операций, поскольку они более гибкие, легче фильтруются и могут быть детально назначены пользователям. Но если вопрос, на который ищется ответ: "Является ли текущий пользователь редактором?", тогда использование current_user_can
абсолютно нормально, фактически, это именно тот способ, который следует использовать.

@gmazzap - вообще-то, использование current_user_can()
для проверки роли - это не "совершенно нормально". Если бы это было так, зачем бы в документации функции нужно было указывать "эта практика не рекомендуется, так как может привести к ненадежным результатам". То, что что-то "работает", не делает это хорошей или приемлемой практикой. Интернет уже полон плохих практик программирования, выдаваемых за приемлемые. Пожалуйста, не добавляйте к этому.

@butlerblog вы знаете, что Codex пишется участниками? Я программирую для WordPress 16 лет, и количеством ошибок, которые я нашел в Codex за эти годы, я мог бы написать книгу. Тем не менее, это не ошибка, а просто плохо написано. Как я уже писал, практика не рекомендуется для ответа на вопрос: "разрешено ли текущему пользователю делать X?", потому что если это то, что вам нужно узнать, проверка роли действительно даст ненадежные результаты. Но если вы хотите ответить на вопрос "Есть ли у этого пользователя роль X?", что является другим вопросом, тогда current_user_can()
- это правильный способ.

Я не ссылаюсь на codex. Codex не только технически устарел, то, о чем мы говорим, исходит непосредственно из встроенной документации в Core и находится в документации для разработчиков, которая имеет значительно больший контроль, чем codex. Кроме того, поощрение такого использования этой функции приводит к другим плохим привычкам в неправильном использовании ролей против возможностей, примеры которых изобилуют по всему интернету. Вы имеете право на свое мнение, но нам придется согласиться с тем, что мы не согласны.

Извините, если это технически устарело, какой способ вы используете в WordPress для проверки, имеет ли пользователь определенную роль? @butlerblog Обратите внимание, что я не спрашиваю, как проверить, авторизован ли пользователь для выполнения операции, а именно - как проверить, имеет ли пользователь роль или нет.

Когда я сказал "технически устарело", я конкретно имел в виду вашу ссылку на codex. Использование current_user_can()
не является устаревшим - оно никогда не предназначалось для проверки роли - так было с WordPress 2.0, и это отмечено в коде и в документации для разработчиков. Чтобы проверить, имеет ли пользователь роль (для чего практически нет веских причин), это массив в объекте: $user->roles
. Например: in_array( 'some_role', $user->roles );
Но проверка ролей ведет к плохим привычкам. Роли предназначены для массового назначения группы возможностей пользователю, проверять следует именно возможности.

Как указано в ответе @butlerblog, вам не следует использовать current_user_can для проверки роли
Это замечание специально добавлено в PHP документацию функции has_cap
, которая вызывается через current_user_can
Хотя проверка роли вместо возможности частично поддерживается, такая практика не рекомендуется, так как может привести к ненадежным результатам.
ПРАВИЛЬНЫЙ способ сделать это - получить пользователя и проверить $user->roles
, вот так:
if( ! function_exists( 'current_user_has_role' ) ){
function current_user_has_role( $role ) {
$user = get_userdata( get_current_user_id() );
if( ! $user || ! $user->roles ){
return false;
}
if( is_array( $role ) ){
return array_intersect( $role, (array) $user->roles ) ? true : false;
}
return in_array( $role, (array) $user->roles );
}
}
Вот несколько вспомогательных функций, которые я использую для этого (так как иногда мне нужен не только текущий пользователь):
if( ! function_exists( 'current_user_has_role' ) ){
function current_user_has_role( $role ){
return user_has_role_by_user_id( get_current_user_id(), $role );
}
}
if( ! function_exists( 'get_user_roles_by_user_id' ) ){
function get_user_roles_by_user_id( $user_id ) {
$user = get_userdata( $user_id );
return empty( $user ) ? array() : $user->roles;
}
}
if( ! function_exists( 'user_has_role_by_user_id' ) ){
function user_has_role_by_user_id( $user_id, $role ) {
$user_roles = get_user_roles_by_user_id( $user_id );
if( is_array( $role ) ){
return array_intersect( $role, $user_roles ) ? true : false;
}
return in_array( $role, $user_roles );
}
}
Затем вы можете просто сделать так:
current_user_has_role( 'editor' );
или
current_user_has_role( array( 'editor', 'administrator' ) );

Доступ к свойствам низкого уровня никогда не является хорошей идеей в WP, и это точно не правильный способ. Если вопрос, на который ищется ответ - "Является ли текущий пользователь редактором?", тогда использование current_user_can
вполне подходит, фактически, это именно тот путь, по которому следует идти. То, что предпочтительнее использовать возможности для "защиты" операций - это другая тема. Знание роли пользователя может быть правомерным, и в этом случае использование current_user_can
вполне допустимо.

@gmazzap тогда почему в документации current_user_can
конкретно говорится: "Хотя проверка определенных ролей вместо возможностей частично поддерживается, эта практика не рекомендуется, так как может привести к ненадежным результатам." Похоже, что документация и ваш комментарий противоречат друг другу, хотя я понимаю, что вы имеете в виду. При этом $roles
является публичным свойством объекта WP_User
с версии 2.0.0. https://developer.wordpress.org/reference/functions/current_user_can/

документация относится к тому факту, что, например, редактор обычно может редактировать записи. Поэтому вы можете быть склонны проверять, является ли пользователь редактором, чтобы разрешить редактирование записи. Это неправильно, потому что возможность могла быть отфильтрована так, что пользователь, несмотря на то, что он редактор, не должен редактировать запись. И наоборот, подписчику может быть разрешено редактировать записи или только конкретную запись. Проверка возможностей гарантирует, что эти ожидаемые результаты соблюдаются.

Тем не менее, вопрос "Является ли этот пользователь редактором?" все еще может быть правомерным. Вы не должны задавать его для определения того, разрешено ли пользователю что-либо делать, но вы можете задать этот вопрос по какой-то другой причине. И если это так, то использование current_user_can
с названием роли вполне подходит.

Что касается ролей, да, это публичное свойство, на наличие которого можно рассчитывать, но current_user_can
имеет фильтры, например, https://developer.wordpress.org/reference/hooks/user_has_cap/ или https://developer.wordpress.org/reference/hooks/map_meta_cap/. Если плагин или что-либо еще использует эти фильтры для изменения того, что возвращает current_user_can
, то при прямой проверке свойства ролей вы пропустите эти фильтры, и таким образом снизите совместимость вашего кода с кодом других разработчиков.

Для администратора
$current_user = wp_get_current_user();
if (!in_array('administrator', $current_user->roles)) {
//выполнить что-то
}
Для редактора
$current_user = wp_get_current_user();
if (!in_array('editor', $current_user->roles)) {
//выполнить что-то
}
Обратите внимание, что это работает только если вы хотите проверить роли текущего пользователя. Если вам нужно проверить роли для любого другого конкретного пользователя, вам необходимо использовать get_user_by (https://developer.wordpress.org/reference/functions/get_user_by/) или аналогичные методы для получения пользователя, которого вы хотите проверить

<?php
// Проверяем, имеет ли пользователь роль редактора
if( current_user_can('editor')) :
echo "добро пожаловать";
// Проверяем, имеет ли пользователь роль участника
elseif( current_user_can('member')) :
echo "добро пожаловать";
// Если нет прав доступа, показываем сообщение для входа
else :
wp_die("<h2>Чтобы просмотреть эту страницу, вам необходимо сначала <a href='". wp_login_url(get_permalink()) ."' title='Войти'>войти в систему</a></h2>");
endif;
?>

Было бы здорово, если бы вы могли объяснить, как это помогает автору вопроса.

Вы можете разрешить просмотр страницы только "редактору" или "участнику", разместив этот код непосредственно в generic-page.php

Пожалуйста, не просто оставляйте код. Добавьте комментарии и объяснение, как это решает проблему спрашивающего.

Правильные ответы на приведенное выше решение-вопрос по базовому программированию else:
if( current_user_can('administrator')) {
<!-- только администратор увидит это сообщение -->
} else {
if( wp_get_current_user('editor')) {
<!-- только редактор, но не администратор увидит это сообщение -->
?>
<style type="text/css">#perhapsDIVremovalidentifier{
display:none;
</style>
}
<?php
} else {
<!-- пользователь не является ни редактором, ни администратором -->
}}
Кратко: Администратор найден, но если мы добавим редактора, то администратор также будет найден. Поэтому мы просто пропускаем администратора и идентифицируем только редактора.
Помните, что вы всегда должны использовать этот код для вызова вышеуказанного, чтобы минимизировать использование процессора:
if(is_user_logged_in()){}
