L'Editor può creare qualsiasi nuovo utente eccetto l'amministratore
Ho configurato un sito WordPress per un cliente. Il cliente ha il ruolo di Editor, tuttavia ho installato il plugin Members e gli ho dato la capacità di aggiungere nuovi utenti nell'amministrazione di WP. Questo sta funzionando perfettamente.
La domanda che ho è che vorrei che il cliente avesse la possibilità di creare nuovi utenti con i ruoli di Contributor, Subscriber, Editor e Author, ma NON Amministratore. I nuovi utenti che il cliente crea non dovrebbero avere il ruolo di Amministratore. È possibile nascondere questa opzione in qualche modo?
Grazie Vayu

In realtà è abbastanza semplice. Devi filtrare tramite map_meta_caps
per impedire agli editor di creare/modificare gli amministratori, e rimuovere il ruolo di amministratore dall'array dei 'editable roles'. Questa classe, come plugin o nel file functions.php del tuo tema, fa esattamente questo:
class JPB_User_Caps {
// Aggiungi i nostri filtri
function __construct(){
add_filter( 'editable_roles', array($this, 'editable_roles'));
add_filter( 'map_meta_cap', array($this, 'map_meta_cap'), 10, 4);
}
// Rimuovi 'Administrator' dalla lista dei ruoli se l'utente corrente non è un amministratore
function editable_roles( $roles ){
if( isset( $roles['administrator'] ) && !current_user_can('administrator') ){
unset( $roles['administrator']);
}
return $roles;
}
// Se qualcuno sta cercando di modificare o eliminare un amministratore e quell'utente non è un amministratore, non permetterlo
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();
MODIFICA
Ok, ho indagato sul perché permetteva ancora l'eliminazione degli utenti. Sembra che delete_user sia gestito in modo leggermente diverso da edit_user; ho modificato il metodo map_meta_cap per risolvere questo problema. Ho testato su WordPress 3.0.3 e questo codice impedirà a chiunque tranne agli amministratori di eliminare, modificare o creare un amministratore.
MODIFICA 2
Ho aggiornato il codice seguendo la risposta di @bugnumber9 qui sotto. Per favore, vai a votare quella risposta!

Qualcuno può verificare che questo codice impedisca ad altri di eliminare gli amministratori? Non riesco a riprodurre quel comportamento. Previene la modifica, ma il link "elimina" compare ancora al passaggio del mouse, e WP permette all'utente di procedere con l'eliminazione...

@somatic - hai colto nel segno. Grazie per averlo fatto notare. Il problema è ora risolto.

Anch'io ho bisogno di fare questo ma non sono sicuro dove inserire questo codice! Nel functions.php? Se no, come potrebbe essere fatto per funzionare dal functions.php? saluti, Dc

se qualcun altro sta cercando di limitare ulteriori ruoli, basta aggiungere una riga aggiuntiva per ruolo sotto questa linea: unset( $roles['administrator']);
... quindi dopo questa riga puoi aggiungere ad esempio: unset( $roles['editor']);

Ha funzionato perfettamente in 3.4.1, grazie! Assicurati di aggiungere le capability per create_users, delete_users, add_users, remove_users, edit_users, list_users e promote_users

Ottimo codice. Per chi lo utilizza, assicuratevi di vedere la piccola modifica qui sotto di @bugnumber9. (Forse John P Block modificherà il suo codice?)

Nonostante abbia circa 7 anni, questo thread può essere facilmente trovato su Google e fornisce ancora una soluzione funzionante. Mi riferisco al codice fornito da @John P Bloch.
Detto questo, con PHP 7 produce un errore non critico (PHP Deprecated) come segue:
PHP Deprecated: I metodi con lo stesso nome della loro classe non saranno più costruttori in una versione futura di PHP; JPB_User_Caps ha un costruttore deprecato in ...
Per risolvere questo problema, basta sostituire questo pezzo:
// Aggiungi i nostri filtri
function JPB_User_Caps(){
add_filter( 'editable_roles', array(&$this, 'editable_roles'));
add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'),10,4);
}
con questo:
// Aggiungi i nostri filtri
function __construct() {
add_filter( 'editable_roles', array(&$this, 'editable_roles') );
add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'), 10, 4 );
}
Questo risolverà il problema.

Stavo cercando una soluzione in cui l'Editor potesse modificare solo i menu E creare/modificare utenti senza bisogno di un plugin. Alla fine ho creato questa soluzione per chi fosse interessato.
// Personalizza il ruolo 'Editor' per avere la capacità di modificare i menu, aggiungere nuovi utenti
// e altro ancora.
class Custom_Admin {
// Aggiunge i nostri filtri
public function __construct(){
// Permette all'editor di modificare le opzioni del tema (es. 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()) {
// Disabilita l'accesso alle pagine di tema/widgets se non è un amministratore
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(__('Non hai i permessi sufficienti per accedere a questa pagina.'));
}
public function modify_menus()
{
remove_submenu_page( 'themes.php', 'themes.php' ); // nasconde il sottomenu di selezione del tema
remove_submenu_page( 'themes.php', 'widgets.php' ); // nasconde il sottomenu dei widgets
// Menu Aspetto
global $menu;
global $submenu;
if (isset($menu[60][0])) {
$menu[60][0] = "Menu"; // Rinomina Aspetto in Menu
}
unset($submenu['themes.php'][6]); // Personalizza
}
// Rimuove 'Amministratore' dalla lista dei ruoli se l'utente corrente non è un amministratore
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;
}
// Se qualcuno sta cercando di modificare o eliminare un amministratore e l'utente non è un amministratore, non permetterlo
public function map_meta_cap( $caps, $cap, $user_id, $args ){
// $args[0] == altro_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';
}
// Non permettere a un non amministratore di modificare un amministratore
$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;
}
// Non permettere a un non amministratore di eliminare un amministratore
$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;
}
// Se l'utente corrente si chiama admin o administrative ed è un 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();

La soluzione di @John P Bloch funziona ancora bene, ma ho pensato di aggiungere anche il mio piccolo filtro per 'map_meta_cap'. Un po' più breve e pulito, almeno per i miei occhi ;)
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 ); // Controllo PHP 7 per variabile 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 );
