# Rejeter la capacité d’un agent dont la langue déclarée n’est pas activée

> Architecture d'un contrôle qui rejette une capacité d'agent WordPress dès que sa langue déclarée ne correspond à aucune langue active du site.

- Auteur : Clément Hadrot
- Publié le : 2026-02-15
- Mis à jour le : 2026-02-15
- Catégorie : Multilingue
- URL : https://wpmoderne.dev.wordpress-developpement.fr/multilingue/rejeter-capacite-agent-langue-non-activee/

## L’essentiel

- Une capacité déclarée pour une langue absente du site doit être rejetée avant exécution
- Le contrôle se place à l'enregistrement, pas seulement à l'exécution
- La liste des langues actives doit être la source de vérité, jamais codée en dur

WordPress 6.9, sorti en décembre 2025, a introduit l'Abilities API : un registre central qui permet à un site d'exposer des capacités (« abilities ») consommables par des agents, potentiellement via un adaptateur MCP côté site. Une capacité déclare notamment le format des données qu'elle attend et produit, mais rien dans le cœur de l'API n'impose qu'une capacité liée à une langue vérifie que cette langue est bien active sur le site cible.

Sur un projet où plusieurs capacités personnalisées ont été enregistrées pour un site multilingue Polylang (résumer un article, générer une réponse dans la langue du visiteur, rechercher du contenu par langue), l'absence de ce contrôle a permis à un agent externe d'invoquer une capacité en déclarant une langue absente de la configuration du site, produisant un résultat silencieusement dégradé plutôt qu'une erreur explicite.

## Le scénario problématique

Le site gère trois langues actives via Polylang : français, anglais, allemand. Une des capacités enregistrées, `generer-reponse-langue`, accepte un paramètre `langue` et produit un texte dans cette langue à partir du contenu du site. Un agent, mal configuré côté appelant, a invoqué cette capacité avec `langue: "es"` (espagnol), une langue qui n'existe simplement pas sur ce site.

Sans contrôle explicite, la capacité a néanmoins retourné une réponse : le code interne, faute de contenu en espagnol, s'est replié silencieusement sur la langue par défaut du site (le français), sans jamais signaler à l'agent appelant que la langue demandée n'était pas disponible. Ce comportement, découvert lors d'un test d'intégration, aurait pu passer inaperçu en production si l'agent appelant avait, de son côté, présenté cette réponse en français comme si elle était en espagnol.

## L'architecture du contrôle

> L'essentiel à retenir : Une capacité déclarée pour une langue absente du site doit être rejetée avant exécution ; Le contrôle se place à l'enregistrement, pas seulement à l'exécution ; La liste des langues actives doit être la source de vérité, jamais codée en dur

Le principe retenu : la vérification de la langue déclarée doit intervenir avant l'exécution de la capacité, au niveau de son enregistrement, jamais dans la logique métier de la capacité elle-même. Cela évite de dupliquer le contrôle dans chaque capacité qui accepte un paramètre de langue.

```
arborescence du contrôle mis en place :

  wp-content/mu-plugins/
  └── abilities-multilingue/
      ├── abilities-multilingue.php     (point d'entrée, hooks)
      ├── inc/
      │   ├── class-validateur-langue.php   (vérifie la langue déclarée)
      │   └── class-registre-capacites.php  (enregistre les abilities)
      └── README.md

  flux d'une invocation :

  Agent externe
      │  invoque une capacité avec un paramètre "langue"
      ▼
  Registre des abilities (WordPress 6.9)
      │  déclenche le callback de permission de la capacité
      ▼
  Validateur de langue (filtre sur le callback de permission)
      │  compare la langue déclarée à pll_languages_list()
      ├─ langue active   → exécution normale de la capacité
      └─ langue absente  → rejet explicite avant exécution
```

Le point clé de cette architecture : le contrôle s'appuie sur le mécanisme de permission déjà prévu par l'Abilities API pour chaque capacité enregistrée, plutôt que d'ajouter une vérification ad hoc dans le corps de chaque fonction de capacité.

## L'implémentation du validateur

```
<?php
declare(strict_types=1);

add_filter(
    'wp_ability_generer_reponse_langue_permission_callback',
    function ( $autorise, $parametres ) {
        if ( ! isset( $parametres['langue'] ) ) {
            return new WP_Error(
                'langue_manquante',
                'Le paramètre langue est obligatoire pour cette capacité.'
            );
        }

        $langues_actives = function_exists( 'pll_languages_list' )
            ? pll_languages_list()
            : array();

        if ( ! in_array( $parametres['langue'], $langues_actives, true ) ) {
            return new WP_Error(
                'langue_non_activee',
                sprintf(
                    'La langue "%s" n\'est pas active sur ce site. Langues disponibles : %s',
                    $parametres['langue'],
                    implode( ', ', $langues_actives )
                )
            );
        }

        return $autorise;
    },
    10,
    2
);
```

Ce filtre retourne un objet `WP_Error` explicite dès que la langue déclarée ne figure pas dans la liste retournée par `pll_languages_list()`, la fonction de Polylang qui expose les codes de langue actifs. L'agent appelant reçoit alors une erreur claire plutôt qu'une réponse dégradée silencieuse.

## Pourquoi la source de vérité ne doit jamais être codée en dur

Une tentation fréquente consiste à coder en dur la liste des langues acceptées directement dans le validateur, sous la forme d'un tableau `['fr', 'en', 'de']`. Ce choix introduit un couplage fragile : toute modification de la configuration linguistique du site (ajout ou retrait d'une langue via l'interface de Polylang) désynchronise silencieusement le validateur de la réalité du site, jusqu'à ce qu'un incident similaire au premier se reproduise. L'appel à `pll_languages_list()` à chaque invocation garantit que le contrôle reste synchronisé avec la configuration réelle, sans mise à jour manuelle du code lors d'un changement de langue active.

> Un registre de capacités d'agent n'a aucune raison de connaître par lui-même les langues actives d'un site : c'est au code du site de porter cette connaissance et de refuser explicitement ce qu'il ne peut pas garantir, plutôt que de laisser une capacité se replier silencieusement sur un comportement par défaut non demandé.

## Ce que ce contrôle ne couvre pas

Ce validateur vérifie que la langue déclarée existe sur le site ; il ne vérifie pas que le contenu nécessaire à la capacité existe réellement dans cette langue précise. Une capacité pourrait très bien accepter une langue active mais échouer ensuite faute de contenu traduit pour l'article demandé. Ce second contrôle relève de la logique métier propre à chaque capacité, pas du validateur générique de langue décrit ici, qui se limite à écarter le cas le plus trompeur : une langue qui n'existe tout simplement pas sur ce site.

## En résumé

L'Abilities API de WordPress 6.9 ne garantit par elle-même aucune cohérence entre la langue déclarée par un agent appelant et les langues réellement actives sur le site. Placer un validateur au niveau du callback de permission de chaque capacité liée à une langue, appuyé sur la source de vérité réelle (`pll_languages_list()` ou son équivalent selon l'extension multilingue utilisée), permet de rejeter explicitement une invocation incohérente avant qu'elle ne produise un résultat dégradé et silencieux.
