Как разрешить редактору редактировать только страницу конфиденциальности и настройки?
В моей установке WordPress (4.9.8.)
роль редактора не имеет прав на редактирование страницы конфиденциальности.
Это можно исправить, добавив следующий код в functions.php
:
$role_object = get_role( 'editor' );
$role_object->add_cap( 'manage_privacy_options', true );
$role_object->add_cap( 'manage_options' ); // это должно быть активно, чтобы предыдущее право работало
Но теперь у редактора появляется значительно больше прав, чем просто редактирование страницы конфиденциальности.
Есть ли другой способ предоставить доступ роли редактора
с помощью нескольких строк PHP кода?
В качестве временного решения я использую этот плагин: https://wordpress.org/plugins/manage-privacy-options/
Еще одно временное решение - просто не выбирать страницу конфиденциальности в настройках.

Редактирование страницы политики конфиденциальности ограничено возможностью manage_privacy_options
, как указано в комментарии к файлу ядра WordPress wp-includes/capabilities.php
:
/*
* Установка страницы политики конфиденциальности требует `manage_privacy_options`,
* поэтому её редактирование тоже должно требовать этого.
*/
if ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post->ID ) {
$caps = array_merge( $caps, map_meta_cap( 'manage_privacy_options', $user_id ) );
}
Чтобы разрешить пользователям с ролями , которые могут редактировать страницы (в одиночных и мультисайтовых инсталляциях), редактировать и удалять страницу политики конфиденциальности, необходимо переопределить массив editor
и administrator
$caps
:
add_filter('map_meta_cap', 'custom_manage_privacy_options', 1, 4);
function custom_manage_privacy_options($caps, $cap, $user_id, $args)
{
if (!is_user_logged_in()) return $caps;
if ('manage_privacy_options' === $cap) {
$manage_name = is_multisite() ? 'manage_network' : 'manage_options';
$caps = array_diff($caps, [ $manage_name ]);
}
return $caps;
}
Обновление: Разрешить пользователям с ролью editor
или administrator
редактировать и удалять страницу политики конфиденциальности (что по умолчанию невозможно в мультисайтовых инсталляциях):
add_filter('map_meta_cap', 'custom_manage_privacy_options', 1, 4);
function custom_manage_privacy_options($caps, $cap, $user_id, $args)
{
if (!is_user_logged_in()) return $caps;
$user_meta = get_userdata($user_id);
if (array_intersect(['editor', 'administrator'], $user_meta->roles)) {
if ('manage_privacy_options' === $cap) {
$manage_name = is_multisite() ? 'manage_network' : 'manage_options';
$caps = array_diff($caps, [ $manage_name ]);
}
}
return $caps;
}

О, выглядит очень умно.. 1. $caps = array_diff($caps, [ $manage_name ]);
действительно ограничивает все другие права manage_options
? И разрешает только редактирование настроек конфиденциальности? 2. administrator
в этом не нуждается, так как это право уже включено, верно?

@AndréKelling 1. Хук map_meta_cap
работает на основе отдельных записей. Другие записи не имеют ограничения manage_privacy_options
, поэтому его можно спокойно удалить. Подробнее здесь.
2. В среде WordPress Multisite только супер-администраторы могут редактировать страницу политики конфиденциальности. Как вы отметили, это не относится к одиночным установкам.

@AndréKelling У вас есть ещё вопросы по моему ответу? Если нет, пожалуйста, примите ответ, чтобы отметить этот вопрос как решённый :)

Нет, извини, не нашёл времени проверить это. Сделаю немедленно!

Это работает довольно хорошо, но не будет ли лучше дополнительно проверять роль пользователя... ведь это повлияет на данное разрешение для всех пользователей, не так ли?

@GDY Хорошее замечание. Я предполагал, что только редакторы и администраторы могут редактировать страницы. Добавил проверку роли пользователя в свой ответ.

Собственно, вопрос касается роли редактора (который в стандартных установках не может редактировать страницу конфиденциальности), поэтому ответ должен охватывать и редакторов, и администраторов.

Большое спасибо за решение. Для тех, кто хочет разрешить WooCommerce Shop Managers редактировать политику конфиденциальности, добавьте "shop_manager" в array_intersect во втором примере.

Я знаю, что add_action
является алиасом для add_filter
, но поскольку фильтр map_meta_cap
определяется с помощью apply_filters
, я думаю, что для краткости следует заменить add_action()
на add_filter()
.

Этот код вызывает фатальную ошибку (Fatal error: Uncaught TypeError: array_intersect(): Argument #2 must be of type array, null given ...snip... /wp-admin/user-new.php(195): edit_user()
) при создании новой учетной записи пользователя. Похоже, что пользователь может быть null. Я добавил дополнительную проверку после вызова get_userdata()
, которая оборачивает его следующим образом: if ($user_meta && isset($user_meta->roles) && is_array($user_meta->roles)) { }

Спасибо @Sven за отличное решение, оно работает хорошо, но у меня возникла проблема, когда пользователь еще не вошел в систему, действие map_meta_cap все равно срабатывало, что приводило к ошибке "502 Bad Gateway". Я добавил проверку is_user_logged_in()
перед этим, вот так:
if (is_user_logged_in()){
add_action('map_meta_cap', 'custom_manage_privacy_options', 1, 4);
}
Возможно, это из-за моей конфигурации сервера (nginx), что приводит к этой ошибке, но если у кого-то возникнет такая же проблема, вот решение.

Предоставленное решение сработало. Однако эта строка:
if (array_intersect(['editor', 'administrator'], $user_meta->roles)) {
Вызывала следующую ошибку:
array_intersect(): Expected parameter 2 to be an array, null given in
Поэтому я немного изменил код, чтобы убедиться, что оба значения являются валидными массивами (полный код):
add_action('map_meta_cap', 'custom_manage_privacy_options', 1, 4);
function custom_manage_privacy_options($caps, $cap, $user_id, $args) {
if ( !is_user_logged_in() ) return $caps;
$target_roles = array('editor', 'administrator');
$user_meta = get_userdata($user_id);
$user_roles = ( array ) $user_meta->roles;
if ( array_intersect($target_roles, $user_roles) ) {
if ('manage_privacy_options' === $cap) {
$manage_name = is_multisite() ? 'manage_network' : 'manage_options';
$caps = array_diff($caps, [ $manage_name ]);
}
}
return $caps;
}

Я не вижу, что ты изменил. Если $user_meta->roles равно null, ты всё равно передаёшь null в array_intersect здесь.

Раз мы сначала убеждаемся, что пользователь залогинен, $user_meta->roles никогда не может быть null? Я думал, что проблема была из-за использования $user_meta->roles напрямую в array_intersect, поэтому сначала сохранил это в переменную. Я больше не получаю сообщений об ошибках, так что похоже это исправило проблему.

⚠ Внимание! Пока эта ошибка не исправлена, этот ответ, хотя концептуально верный, не будет работать! ⚠
На мой взгляд, теперь это лучше выполнять с помощью wp-cli
.
Например, расширить роль редактора:
wp cap add editor manage_privacy_options
Или только для одного пользователя:
wp user add-cap USER_ID manage_privacy_options

Ого, похоже, это не работает :-( Если кто-то может прокомментировать, подтвердить... Пахнет багом.

Нашел виновника, довольно старый баг :-/
