Edytor może utworzyć każdego nowego użytkownika oprócz administratora

36

Skonfigurowałem witrynę WordPress dla klienta. Klient pełni rolę edytora, jednak zainstalowałem wtyczkę Members i dałem klientowi możliwość dodawania nowych użytkowników do administratora WP. To działa dobrze.

Mam pytanie, czy chciałbym, aby klient miał możliwość tworzenia nowego użytkownika, podobnie jak w roli współautora, subskrybenta, redaktora i autora, ale NIE administratora. Nowi użytkownicy tworzeni przez klienta nie powinni mieć roli administratora. Czy można jakoś ukryć tę opcję?

Dzięki Vayu

Vayu
źródło
2
Połącz wtyczkę, której używasz. Miałem problemy z ustaleniem, którego dotyczy.
hakre

Odpowiedzi:

39

To jest naprawdę dość łatwe. Musisz przefiltrować map_meta_capsi powstrzymać redaktorów przed tworzeniem / edytowaniem administratorów i usunąć rolę administratora z tablicy „edytowalnych ról”. Ta klasa, jako wtyczka lub plik funkcji w pliku theme.php, zrobiłaby to:

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();

EDYTOWAĆ

Ok, więc zastanowiłem się, dlaczego pozwalało to na usunięcie użytkownika. Wygląda na to, że delete_user jest obsługiwany nieco inaczej niż edit_user; Zmodyfikowałem metodę map_meta_cap, aby obejść ten problem. Testowałem na wersji 3.0.3, a to uniemożliwi faktyczne usuwanie, edytowanie lub tworzenie administratora przez osoby inne niż administratorzy.

EDYCJA 2

Zaktualizowałem kod, aby odzwierciedlał odpowiedź @ bugnumber9 poniżej. Proszę, odpowiedzcie pozytywnie!

John P. Bloch
źródło
Czy ktoś może sprawdzić, czy ten kod zapobiega usuwaniu administratorów przez innych? Nie mogę odtworzyć tego zachowania. Uniemożliwia to edycję, ale nadal pojawia się link „usuń”, a WP pozwala użytkownikowi przejść przez usunięcie ...
somat
@somatic - byłeś na miejscu. Dzięki za zwrócenie na to uwagi. Problem został już rozwiązany.
John P Bloch,
muszę to zrobić, ale nie jestem pewien, gdzie umieściłem ten kod! W funkcji.php? Jeśli nie, to jak można to zrobić, aby działało z funkcji.php? najlepszy, Dc
v3nt
@ Daniel przeczytał pierwszy akapit.
John P Bloch,
1
Działa świetnie w 3.4.1, dzięki! Pamiętaj, aby dodać możliwości dla create_users, delete_users, add_users, remove_users, edit_users, list_users i promot_users
Jon Raasch,
8

Pomimo tego, że ma około 7 lat, ten wątek można łatwo przejrzeć i nadal zapewnia działające rozwiązanie. Mam na myśli kod dostarczony przez @John P Bloch.

To powiedziawszy, w PHP 7 powoduje błąd niekrytyczny (PHP przestarzałe) w następujący sposób:

Przestarzałe PHP: Metody o tej samej nazwie co ich klasa nie będą konstruktorami w przyszłej wersji PHP; JPB_User_Caps ma przestarzały konstruktor w ...

Aby to naprawić, po prostu wymień ten kawałek:

// 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);
  }

z tym:

// 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 );
  }

To rozwiąże problem.

bugnumber9
źródło
1
Dziekuję Dziekuję Dziękuję. Doceniam poświęcenie jakości kodu i zaktualizowałem swoją odpowiedź, aby przypadkowi pracownicy Google również otrzymali notatkę. Rządzisz!
John P Bloch,
3

Szukałem rozwiązania, w którym edytor mógłby edytować tylko menu ORAZ tworzyć / edytować użytkowników bez potrzeby używania wtyczki. Więc skończyło się na tym, że są zainteresowani.

// 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();
SilbinaryWolf
źródło
1

@John P Rozwiązanie Blochsa nadal działa dobrze, ale pomyślałem, że wrzucę również mój mały filtr dla 'map_meta_cap'. Tylko trochę krótszy i czystszy, przynajmniej dla moich oczu;)

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 );
rassoh
źródło