Редактор може створити будь-якого нового користувача, крім адміністратора


36

Я створив сайт WordPress для клієнта. Клієнт має роль редактора, однак я встановив плагін Members і надав клієнту можливість додавати нових користувачів до адміністратора WP. Це працює просто чудово.

У мене є питання, що я хотів би, щоб клієнт мав можливість створювати нового користувача, як це стосується ролей учасника, підписника, редактора та автора, але НЕ адміністратора. Нові користувачі, які створює клієнт, не повинні виконувати роль адміністратора. Чи можливо якось приховати цей варіант?

Дякую Ваю


2
Зв’яжіть плагін, який ви використовуєте, у мене виникли проблеми, щоб дізнатися, на який ви звертаєтесь.
хакре

Відповіді:


39

Насправді це досить просто. Потрібно фільтрувати в map_meta_capsредакторах і не дозволяти їм створювати / редагувати адміністратори та видаляти роль адміністратора з масиву "редагованих ролей". Цей клас, як плагін або у вашому файлі function.php, зробить це:

class JPB_User_Caps {

  // Add our filters
  function __construct(){
    add_filter( 'editable_roles', array($this, 'editable_roles'));
    add_filter( 'map_meta_cap', array($this, 'map_meta_cap'), 10, 4);
  }

  // Remove 'Administrator' from the list of roles if the current user is not an admin
  function editable_roles( $roles ){
    if( isset( $roles['administrator'] ) && !current_user_can('administrator') ){
      unset( $roles['administrator']);
    }
    return $roles;
  }

  // If someone is trying to edit or delete and admin and that user isn't an admin, don't allow it
  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();

EDIT

Гаразд, я роздивився, чому це дозволяє пропускати користування видаленням. Схоже, видалення_користувача обробляється трохи інакше, ніж редагування_користувача; Я змінив метод map_meta_cap, щоб обійти це. Я перевірив версію 3.0.3, і це не дозволить комусь, окрім адміністраторів, фактично видаляти, редагувати чи створювати адміністратора.

EDIT 2

Я оновив код, щоб відобразити відповідь @ bugnumber9 нижче. Будь ласка, ідіть, дайте цю відповідь підсумком!


Чи може хтось перевірити, що цей код заважає іншим видаляти адміністраторів? Я не можу відтворити таку поведінку. Це не заважає їм редагувати, але посилання "видалити" навести курсор все ще з'являється, і WP дозволяє користувачеві пройти процес видалення ...
соматичне

@somatic - ви потрапили на місце. Дякуємо, що вказали на це. Питання виправлено зараз.
Джон П Блох

мені потрібно це зробити також, але не знаю, куди я поставив цей код! У function.php? Якщо ні, як це можна зробити для роботи з function.php? кращий, Dc
v3nt

@daniel прочитав перший абзац.
Джон П Блох

1
Працював чудово в 3.4.1, дякую! Не забудьте додати можливості для create_users, delete_users, add_users, remove_users, edit_users, list_users та promo_users
Jon Raasch,

8

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

Враховуючи це, під PHP 7 вона створює некритичну помилку (застарілу PHP) наступним чином:

PHP застаріло: методи з тим самим іменем, що і їх клас, не будуть конструкторами в майбутній версії PHP; JPB_User_Caps має застарілий конструктор у ...

Щоб виправити це, просто замініть цю частину:

// Add our filters
  function JPB_User_Caps(){
    add_filter( 'editable_roles', array(&$this, 'editable_roles'));
    add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'),10,4);
  }

з цим:

// Add our filters
  function __construct() {
    add_filter( 'editable_roles', array(&$this, 'editable_roles') );
    add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'), 10, 4 );
  }

Це виправить проблему.


1
Дякую, дякую, дякую. Я ціную відданість якості коду та оновив свою відповідь, щоб випадкові googlers також отримали нагадування. Ти рок!
Джон П Блох

3

Я шукав рішення, де редактор міг би редагувати лише меню І створювати / редагувати користувачів, не потребуючи плагіну. Тож я закінчив робити це для тих, хто цікавиться.

// Customizes 'Editor' role to have the ability to modify menus, add new users
// and more.
class Custom_Admin {
    // Add our filters
    public function __construct(){
        // Allow editor to edit theme options (ie Menu)
        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()) {
            // Disable access to the theme/widget pages if not 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(__('You do not have sufficient permissions to access this page.'));
    }

    public function modify_menus() 
    {
        remove_submenu_page( 'themes.php', 'themes.php' ); // hide the theme selection submenu
        remove_submenu_page( 'themes.php', 'widgets.php' ); // hide the widgets submenu

        // Appearance Menu
        global $menu;
        global $submenu;
        if (isset($menu[60][0])) {
            $menu[60][0] = "Menus"; // Rename Appearance to Menus
        }
        unset($submenu['themes.php'][6]); // Customize
    }

    // Remove 'Administrator' from the list of roles if the current user is not an admin
    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;
    }

    // If someone is trying to edit or delete and admin and that user isn't an admin, don't allow it
    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';
                    }
                    // Do not allow non-admin to edit admin
                    $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;
                    }
                    // Do not allow non-admin to delete admin
                    $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;
    }

    // If current user is called admin or administrative and is an editor
    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();

1

@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 check for variable in $args... 
  if( $other && $other->has_cap('administrator') ) {
    $caps[] = 'do_not_allow';
  }
  return $caps;
}
add_filter('map_meta_cap', 'my_map_meta_cap', 10, 4 );
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.