# Capacités personnalisées WordPress : créer un rôle sur mesure sans tout casser

> Créer un rôle « éditeur de produits » avec des capacités précises plutôt que d'accorder administrator par facilité. Recette pas à pas et pièges des capacités mal héritées.

- Auteur : Clément Hadrot
- Publié le : 2021-06-17
- Mis à jour le : 2021-06-17
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/capacites-personnalisees-role-sur-mesure/

## L’essentiel

- administrator par facilité est le réflexe à bannir
- Un rôle hérite implicitement de ses capacités listées, pas d'un autre rôle
- Toujours prévoir la désinstallation du rôle créé

Un client vendant du mobilier sur mesure via WooCommerce nous demande de créer un accès pour ses deux commerciaux, chargés de mettre à jour les fiches produits (descriptions, prix, stock) sans toucher au reste du site. La solution la plus rapide, et la plus mauvaise, consisterait à leur attribuer le rôle `administrator` « pour ne pas avoir de problème de droits ». C'est pourtant ce que fait la majorité des sites que nous reprenons en maintenance : un rôle unique surdimensionné, distribué par facilité, jamais revu ensuite.

La bonne approche demande quelques minutes de plus mais élimine une classe entière de risques : si le compte d'un commercial est un jour compromis (mot de passe réutilisé, poste infecté), l'attaquant n'hérite que des capacités strictement nécessaires à la gestion des produits, jamais de la possibilité d'installer une extension, de modifier un thème ou de créer un autre compte administrateur.

## Choisir les capacités plutôt que le rôle

WordPress distingue deux notions souvent confondues : le **rôle** (une étiquette, comme `editor` ou `administrator`) et la **capacité** (une permission précise, comme `edit_posts` ou `manage_options`). Un rôle n'est en réalité qu'un ensemble nommé de capacités. Vérifier les droits d'un utilisateur avec `current_user_can( 'manage_options' )` est donc toujours préférable à `current_user_can( 'administrator' )`, qui teste en réalité une capacité fantôme peu fiable plutôt qu'une permission réelle.

Pour notre rôle « éditeur de produits », les besoins réels se limitent à :

- Voir et modifier les produits WooCommerce (type de contenu `product`).
- Gérer les termes de taxonomie associés (catégories et étiquettes de produit).
- Téléverser des images pour illustrer les fiches.
- Consulter (sans modifier) les commandes, pour vérifier un stock réservé.

Rien ne justifie l'accès aux réglages du site, aux extensions, aux thèmes, ni aux comptes d'autres utilisateurs.

## Créer le rôle avec add_role

> L'essentiel à retenir : administrator par facilité est le réflexe à bannir ; Un rôle hérite implicitement de ses capacités listées, pas d'un autre rôle ; Toujours prévoir la désinstallation du rôle créé

```
add_action( 'init', 'moncpt_creer_role_editeur_produits' );

function moncpt_creer_role_editeur_produits() {
    // On ne recrée pas le rôle s'il existe déjà : add_role() échouerait
    // silencieusement, mais on évite aussi de réinitialiser les capacités
    // à chaque chargement, coûteux et inutile.
    if ( get_role( 'editeur_produits' ) ) {
        return;
    }

    add_role(
        'editeur_produits',
        __( 'Éditeur de produits', 'moncpt' ),
        array(
            'read'                   => true,
            'edit_products'          => true,
            'edit_published_products'=> true,
            'upload_files'           => true,
            'assign_product_terms'   => true,
        )
    );
}
```

Ce code doit s'exécuter une seule fois, typiquement dans `register_activation_hook()` plutôt qu'à chaque chargement sur `init` — l'exemple ci-dessus inclut une vérification d'existence précisément pour limiter les écritures répétées en base, mais l'activation reste l'endroit le plus propre pour cette création.

Les capacités `edit_products`, `edit_published_products` et `assign_product_terms` ne sont pas génériques : elles correspondent au type de contenu personnalisé `product` défini par WooCommerce avec des `capability_type` spécifiques. Pour un type de contenu personnalisé maison, les noms de capacités suivent le même principe et se définissent via l'argument `capabilities` de `register_post_type()`.

## Le piège de l'héritage mal compris

Erreur fréquente : croire qu'un rôle personnalisé « hérite » automatiquement des capacités d'un rôle existant si son nom y ressemble, ou que les capacités se cumulent entre rôles attribués simultanément d'une façon intuitive. En réalité, chaque capacité listée dans `add_role()` doit être explicite ; il n'existe aucune notion de rôle parent en WordPress. Un développeur pressé recopie parfois les capacités de `editor` presque intégralement « pour être sûr que ça marche », puis retire une à une celles qui semblent gênantes — une méthode qui laisse invariablement des capacités oubliées, comme `edit_others_posts` ou `delete_others_pages`, sans lien avec le besoin réel.

La bonne méthode part du besoin fonctionnel vers la capacité, jamais l'inverse. Pour vérifier ce qu'un rôle contient réellement une fois créé, WP-CLI évite toute ambiguïté :

```
wp role list --fields=name,role
wp cap list editeur_produits
```

## Vérifier côté code, pas seulement côté rôle

Une fois le rôle créé, chaque écran ou action réservée aux éditeurs de produits doit vérifier la capacité précise, jamais le nom du rôle en dur :

```
// À proscrire : fragile si le rôle est renommé ou si un utilisateur cumule plusieurs rôles
if ( in_array( 'editeur_produits', wp_get_current_user()->roles, true ) ) { /* ... */ }

// À privilégier : robuste et cohérent avec le reste de WordPress
if ( current_user_can( 'edit_products' ) ) { /* ... */ }
```

> Sur ce projet, réduire le rôle à six capacités précises plutôt que d'accorder administrator a aussi eu un effet inattendu et bienvenu : les deux commerciaux ne voyaient plus dans leur tableau de bord que les écrans utiles à leur travail, ce qui a réduit les questions de support autant que le risque.

## Prévoir la désinstallation

Un rôle personnalisé créé par une extension doit être retiré proprement si l'extension est désinstallée, faute de quoi il reste indéfiniment en base, avec des capacités qui ne correspondent plus à rien :

```
register_uninstall_hook( __FILE__, 'moncpt_nettoyer_role_editeur_produits' );

function moncpt_nettoyer_role_editeur_produits() {
    remove_role( 'editeur_produits' );
}
```

## Pour aller plus loin

Cette recette ne couvre pas le fonctionnement général de `current_user_can()` face aux capacités méta (comme `edit_post` appliquée à un article précis via le filtre `map_meta_cap`), déjà traité séparément. Retenez le principe directeur : partir des tâches réellement confiées à un utilisateur, les traduire en capacités précises, et ne jamais accorder par défaut ce qui n'a pas été explicitement justifié.
