Le WordPress d'aujourd'hui, décodé pour les développeurs

Headless & API

map_meta_cap pour faire correspondre une capacité WordPress à un scope d’API

Comment le filtre map_meta_cap, présent depuis les premières versions de WordPress, permet de dériver une logique de scopes d'API proche d'OAuth.

Par Clément Hadrot • 10 octobre 2025 • 4 min de lecture • Aucun commentaire
map_meta_cap pour faire correspondre une capacité WordPress à un scope d'API

Depuis WordPress 2.0, le système de rôles et capacités repose sur une distinction que beaucoup de développeurs découvrent tardivement : les capacités « primitives » comme edit_posts, attribuées globalement à un rôle, et les capacités « méta » comme edit_post (au singulier), qui dépendent du contenu précis visé. C’est le filtre map_meta_cap qui fait le lien entre les deux, en traduisant une vérification méta en une ou plusieurs capacités primitives réellement testées.

Pour un projet headless qui cherche à exposer une API avec des permissions plus fines que le simple « authentifié ou non », comprendre ce mécanisme ouvre une voie naturelle vers une logique de scopes, sans avoir à réinventer un système de permissions parallèle à celui de WordPress.

Comment fonctionne map_meta_cap

Lorsqu’une vérification comme current_user_can( 'edit_post', 42 ) est appelée, WordPress ne se contente pas de vérifier si l’utilisateur possède une capacité nommée edit_post (elle n’existe d’ailleurs dans aucun rôle par défaut). Le cœur de WordPress appelle map_meta_cap(), qui reçoit la capacité demandée, l’identifiant de l’utilisateur, et l’identifiant de l’objet concerné (ici l’article 42), puis retourne un tableau de capacités primitives à vérifier réellement, en tenant compte du contexte : l’article appartient-il à l’utilisateur ? Est-il déjà publié ? L’utilisateur a-t-il la capacité générique edit_others_posts ?

add_filter( 'map_meta_cap', function( $capacites_requises, $capacite, $user_id, $args ) {
    if ( 'edit_post' === $capacite ) {
        $post = get_post( $args[0] );
        if ( $post && (int) $post->post_author !== $user_id ) {
            $capacites_requises[] = 'edit_others_posts';
        }
    }
    return $capacites_requises;
}, 10, 4 );

Dériver un scope d’API à partir de ce mécanisme

Une API à scopes façon OAuth (lecture seule, écriture limitée à ses propres contenus, écriture globale) peut sembler exiger un système entièrement nouveau. En réalité, la logique de map_meta_cap couvre déjà une bonne partie du besoin : un jeton d’application WordPress reste associé à un utilisateur, et cet utilisateur porte des rôles et capacités classiques. Ajouter un scope revient alors à filtrer map_meta_cap pour restreindre davantage les capacités effectives selon le contexte de la requête REST en cours, sans dupliquer la logique métier déjà présente dans le cœur de WordPress.

L'essentiel à retenir : Une capacité méta dépend du contenu ciblé ; Le filtre reçoit l'ID de l'objet concerné ; Base solide pour des scopes granulaires

Un exemple appliqué à une route personnalisée

Imaginez une route REST qui permet à un utilisateur authentifié par mot de passe d’application de modifier uniquement les articles dont il est l’auteur, jamais ceux des autres, même s’il possède par ailleurs la capacité edit_others_posts via son rôle. Ce comportement, qui ressemble à un scope restreint, se code en interceptant map_meta_cap et en vérifiant un marqueur propre à la requête en cours :

add_filter( 'map_meta_cap', function( $capacites_requises, $capacite, $user_id, $args ) {
    if ( 'edit_post' === $capacite && defined( 'REQUETE_SCOPE_LIMITE' ) && REQUETE_SCOPE_LIMITE ) {
        $post = get_post( $args[0] );
        if ( $post && (int) $post->post_author !== $user_id ) {
            return array( 'do_not_allow' );
        }
    }
    return $capacites_requises;
}, 10, 4 );

La capacité fictive do_not_allow est la convention WordPress pour refuser explicitement une action, quel que soit le rôle de l’utilisateur.

Les limites de l’approche

Ce mécanisme reste attaché au système de capacités de WordPress, pensé pour un petit nombre de rôles fixes. Pour une API qui doit gérer de nombreux scopes fins et combinables (lecture des commentaires, écriture des médias, accès aux commandes), une table de correspondance dédiée entre jetons et scopes, consultée en amont de map_meta_cap, apporte plus de clarté qu’un empilement de conditions dans un seul filtre. map_meta_cap reste alors le point d’exécution final, pas le seul lieu de décision.

  • Convient bien à des scopes simples, proches des capacités WordPress existantes.
  • Devient difficile à maintenir au-delà de quelques règles conditionnelles empilées dans le même filtre.
  • Ne remplace pas un vrai système de jetons à durée de vie et à portée limitée pour une API exposée publiquement à des applications tierces.

Pour aller plus loin

La documentation officielle sur developer.wordpress.org détaille l’ensemble des capacités méta reconnues par défaut (edit_post, delete_post, read_post, et leurs équivalents pour les pages et types personnalisés). S’appuyer sur map_meta_cap pour construire une logique de scopes évite de dupliquer un système de permissions parallèle, tout en restant compatible avec les extensions qui, elles aussi, s’appuient sur ce même filtre pour leurs propres vérifications.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi