Редактор может создавать любых новых пользователей, кроме администратора

24 нояб. 2010 г., 12:34:04
Просмотры: 21.8K
Голосов: 42

Я настроил WordPress сайт для клиента. У клиента есть роль Редактора, при этом я установил плагин Members и предоставил клиенту возможность добавлять новых пользователей в админ-панель WordPress. Это работает отлично.

Мой вопрос в том, что я хотел бы дать клиенту возможность создавать новых пользователей с ролями Подписчика, Автора, Редактора и Участника, но НЕ Администратора. Новые пользователи, которых создает клиент, не должны иметь роль Администратора. Возможно ли как-то скрыть этот вариант?

Спасибо Vayu

1
Комментарии

Пожалуйста, укажите ссылку на используемый вами плагин, у меня возникли сложности с определением, о каком именно плагине идет речь.

hakre hakre
24 нояб. 2010 г. 14:22:02
Все ответы на вопрос 4
8
45

На самом деле это довольно просто. Вам нужно добавить фильтры в map_meta_caps, чтобы запретить редакторам создавать/редактировать администраторов, а также удалить роль администратора из массива 'editable roles'. Этот класс, реализованный как плагин или в файле functions.php вашей темы, справится с задачей:

class JPB_User_Caps {

  // Добавляем наши фильтры
  function __construct(){
    add_filter( 'editable_roles', array($this, 'editable_roles'));
    add_filter( 'map_meta_cap', array($this, 'map_meta_cap'), 10, 4);
  }

  // Удаляем 'Administrator' из списка ролей, если текущий пользователь не является администратором
  function editable_roles( $roles ){
    if( isset( $roles['administrator'] ) && !current_user_can('administrator') ){
      unset( $roles['administrator']);
    }
    return $roles;
  }

  // Если кто-то пытается редактировать или удалить администратора, и сам не является администратором - запрещаем
  function map_meta_cap( $caps, $cap, $user_id, $args ){

    switch( $cap ){
        case 'edit_user':
        case 'remove_user':
        case 'promote_user':
            if( isset($args[0]) && $args[0] == $user_id )
                break;
            elseif( !isset($args[0]) )
                $caps[] = 'do_not_allow';
            $other = new WP_User( absint($args[0]) );
            if( $other->has_cap( 'administrator' ) ){
                if(!current_user_can('administrator')){
                    $caps[] = 'do_not_allow';
                }
            }
            break;
        case 'delete_user':
        case 'delete_users':
            if( !isset($args[0]) )
                break;
            $other = new WP_User( absint($args[0]) );
            if( $other->has_cap( 'administrator' ) ){
                if(!current_user_can('administrator')){
                    $caps[] = 'do_not_allow';
                }
            }
            break;
        default:
            break;
    }
    return $caps;
  }

}

$jpb_user_caps = new JPB_User_Caps();

РЕДАКТИРОВАНИЕ

Итак, я разобрался, почему пропускалось удаление пользователей. Оказывается, delete_user обрабатывается немного иначе, чем edit_user. Я изменил метод map_meta_cap, чтобы это учесть. Протестировано на версии 3.0.3 - теперь никто, кроме администраторов, не сможет удалять, редактировать или создавать администраторов.

РЕДАКТИРОВАНИЕ 2

Я обновил код в соответствии с ответом @bugnumber9 ниже. Пожалуйста, проголосуйте за этот ответ!

25 нояб. 2010 г. 00:07:34
Комментарии

Может кто-то подтвердить, что этот код предотвращает удаление администраторов другими пользователями? Я не могу воспроизвести такое поведение. Код действительно предотвращает редактирование, но ссылка "удалить" при наведении все равно отображается, и WordPress позволяет пользователю выполнить удаление...

somatic somatic
15 дек. 2010 г. 14:47:17

@somatic - ты был абсолютно прав. Спасибо, что обратил на это внимание. Проблема теперь исправлена.

John P Bloch John P Bloch
20 дек. 2010 г. 19:24:34

Мне тоже нужно это реализовать, но я не уверен, куда вставлять этот код! В functions.php? Если нет, то как можно сделать, чтобы это работало из functions.php? С уважением, Dc

v3nt v3nt
27 июл. 2011 г. 15:16:42

@daniel прочитай первый абзац.

John P Bloch John P Bloch
27 июл. 2011 г. 17:02:44

если кто-то ещё хочет ограничить дополнительные роли, просто добавьте дополнительную строку для каждой роли под этой строкой: unset( $roles['administrator']); … так после этой строки вы можете добавить, например: unset( $roles['editor']);

User User
4 нояб. 2011 г. 05:32:32

Отлично работает в 3.4.1, спасибо! Убедитесь, что добавили возможности для create_users, delete_users, add_users, remove_users, edit_users, list_users и promote_users

Jon Raasch Jon Raasch
14 сент. 2012 г. 02:11:39

Отличный код. Для тех, кто его использует, обязательно ознакомьтесь с небольшой доработкой от @bugnumber9 ниже. (Может быть, John P Block внесёт правки в свой код?)

Eric Eric
11 июл. 2017 г. 09:40:24

У меня это не сработало.

avia avia
2 авг. 2021 г. 05:33:42
Показать остальные 3 комментариев
1
11

Несмотря на то, что этой ветке уже около 7 лет, её легко найти через Google, и предложенное решение всё ещё работает. Я имею в виду код, предоставленный @John P Bloch.

Однако в PHP 7 этот код вызывает некритическую ошибку (PHP Deprecated):

PHP Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; JPB_User_Caps has a deprecated constructor in ...

Чтобы исправить это, просто замените следующий фрагмент:

// Добавляем наши фильтры
  function JPB_User_Caps(){
    add_filter( 'editable_roles', array(&$this, 'editable_roles'));
    add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'),10,4);
  }

на этот:

// Добавляем наши фильтры
  function __construct() {
    add_filter( 'editable_roles', array(&$this, 'editable_roles') );
    add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'), 10, 4 );
  }

Это исправит проблему.

2 июл. 2017 г. 12:51:59
Комментарии

Спасибо, спасибо, спасибо. Я ценю вашу приверженность качеству кода и обновил свой ответ, чтобы случайные пользователи из поиска тоже были в курсе. Вы просто супер!

John P Bloch John P Bloch
18 июл. 2017 г. 06:04:09
0

Я искал решение, где Редактор мог бы редактировать только меню И создавать/редактировать пользователей без необходимости использования плагина. В итоге я сделал это для тех, кому это интересно.

// Настраивает роль 'Редактор' для возможности изменять меню, добавлять новых пользователей
// и многое другое.
class Custom_Admin {
    // Добавляем наши фильтры
    public function __construct(){
        // Разрешаем редактору редактировать настройки темы (т.е. Меню)
        add_action('init', array($this, 'init'));
        add_filter('editable_roles', array($this, 'editable_roles'));
        add_filter('map_meta_cap', array($this, 'map_meta_cap'), 10, 4);
    }

    public function init() {
        if ($this->is_client_admin()) {
            // Отключаем доступ к страницам тем/виджетов, если пользователь не администратор
            add_action('admin_head', array($this, 'modify_menus'));
            add_action('load-themes.php', array($this, 'wp_die'));
            add_action('load-widgets.php', array($this, 'wp_die'));
            add_action('load-customize.php', array($this, 'wp_die'));

            add_filter('user_has_cap', array($this, 'user_has_cap'));
        }
    }

    public function wp_die() {
        _default_wp_die_handler(__('У вас недостаточно прав для доступа к этой странице.'));
    }

    public function modify_menus() 
    {
        remove_submenu_page( 'themes.php', 'themes.php' ); // скрываем подменю выбора темы
        remove_submenu_page( 'themes.php', 'widgets.php' ); // скрываем подменю виджетов

        // Меню "Внешний вид"
        global $menu;
        global $submenu;
        if (isset($menu[60][0])) {
            $menu[60][0] = "Меню"; // Переименовываем "Внешний вид" в "Меню"
        }
        unset($submenu['themes.php'][6]); // Настроить
    }

    // Удаляем 'Администратор' из списка ролей, если текущий пользователь не админ
    public function editable_roles( $roles ){
        if( isset( $roles['administrator'] ) && !current_user_can('administrator') ){
            unset( $roles['administrator']);
        }
        return $roles;
    }

    public function user_has_cap( $caps ){
        $caps['list_users'] = true;
        $caps['create_users'] = true;

        $caps['edit_users'] = true;
        $caps['promote_users'] = true;

        $caps['delete_users'] = true;
        $caps['remove_users'] = true;

        $caps['edit_theme_options'] = true;
        return $caps;
    }

    // Если кто-то пытается редактировать или удалять администратора, и этот пользователь не админ - запрещаем
    public function map_meta_cap( $caps, $cap, $user_id, $args ){
        // $args[0] == other_user_id
        foreach($caps as $key => $capability)
        {
            switch ($cap)
            {
                case 'edit_user':
                case 'remove_user':
                case 'promote_user':
                    if(isset($args[0]) && $args[0] == $user_id) {
                        break;
                    }
                    else if(!isset($args[0])) {
                        $caps[] = 'do_not_allow';
                    }
                    // Не разрешаем не-админу редактировать админа
                    $other = new WP_User( absint($args[0]) );
                    if( $other->has_cap( 'administrator' ) ){
                        if(!current_user_can('administrator')){
                            $caps[] = 'do_not_allow';
                        }
                    }
                    break;
                case 'delete_user':
                case 'delete_users':
                    if( !isset($args[0])) {
                        break;
                    }
                    // Не разрешаем не-админу удалять админа
                    $other = new WP_User(absint($args[0]));
                    if( $other->has_cap( 'administrator' ) ){
                        if(!current_user_can('administrator')){
                            $caps[] = 'do_not_allow';
                        }
                    }
                    break;
                break;
            }
        }
        return $caps;
    }

    // Если текущий пользователь называется admin или administrative и является редактором
    protected function is_client_admin() {
        $current_user = wp_get_current_user();
        $is_editor = isset($current_user->caps['editor']) ? $current_user->caps['editor'] : false;
        return ($is_editor);
    }
}
new Custom_Admin();
14 нояб. 2014 г. 01:47:53
0

Решение от @John P Blochs по-прежнему работает отлично, но я хотел бы также поделиться своим небольшим фильтром для 'map_meta_cap'. Он немного короче и чище, по крайней мере, на мой взгляд ;)

function my_map_meta_cap( $caps, $cap, $user_id, $args ) {
  $check_caps = [
    'edit_user',
    'remove_user',
    'promote_user',
    'delete_user',
    'delete_users'
  ];
  if( !in_array( $cap, $check_caps ) || current_user_can('administrator') ) {
    return $caps;
  }
  $other = get_user_by( 'id', $args[0] ?? false ); // Проверка PHP 7 на наличие переменной в $args...
  if( $other && $other->has_cap('administrator') ) {
    $caps[] = 'do_not_allow';
  }
  return $caps;
}
add_filter('map_meta_cap', 'my_map_meta_cap', 10, 4 );
26 апр. 2019 г. 00:56:59