# Ajouter un champ de note interne visible seulement par l’équipe, jamais publié

> Un espace d'annotation réservé aux collaborateurs, absent de tout rendu front et de tout export, pour laisser une consigne sans risquer une fuite.

- Auteur : Clément Hadrot
- Publié le : 2025-01-04
- Mis à jour le : 2025-01-04
- Catégorie : Tips
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tips/champ-note-interne-visible-equipe-jamais-publie/

## L’essentiel

- Une meta non enregistrée dans show_in_rest par défaut
- Vérification systématique des capacités avant affichage
- Exclusion explicite des flux RSS et des exports

Sur un site d'actualité juridique, les rédacteurs avaient besoin de laisser des consignes internes sur certains articles sensibles : « attendre confirmation de l'avocat avant publication définitive », ou « vérifier l'orthographe du nom du plaignant avec le service contentieux ». Un champ personnalisé classique, mal cloisonné, s'était une fois retrouvé exposé dans la réponse JSON de l'API REST, visible par n'importe qui inspectant les requêtes réseau du site.

La leçon à en tirer : un champ « interne » doit être conçu dès le départ pour ne fuiter par aucun des canaux que WordPress expose par défaut — le contenu affiché, bien sûr, mais aussi l'API REST, le flux RSS, et les exports au format WXR.

## Créer le champ sans l'exposer à la REST API

Le point de départ classique, une métabox avec une meta, doit explicitement éviter `show_in_rest`. Depuis WordPress 4.7, une meta enregistrée avec `register_post_meta()` peut être exposée dans l'API REST si ce paramètre est activé — il faut donc soit ne pas enregistrer la meta via cette fonction, soit l'enregistrer avec `show_in_rest => false` explicite :

```
add_action( 'init', function () {
    register_post_meta( 'post', '_note_interne_equipe', array(
        'type'         => 'string',
        'single'       => true,
        'show_in_rest' => false,
        'auth_callback' => function () {
            return current_user_can( 'edit_others_posts' );
        },
    ) );
} );
```

Le `auth_callback` est une seconde barrière : même en cas d'appel direct à l'API REST par un utilisateur authentifié, la lecture ou l'écriture de cette meta reste réservée aux profils qui ont la capacité `edit_others_posts`, typiquement les rédacteurs en chef et administrateurs.

## La métabox, réservée aux bons rôles

> L'essentiel à retenir : Une meta non enregistrée dans show_in_rest par défaut ; Vérification systématique des capacités avant affichage ; Exclusion explicite des flux RSS et des exports

```
add_action( 'add_meta_boxes', function () {
    if ( ! current_user_can( 'edit_others_posts' ) ) {
        return;
    }

    add_meta_box(
        'note_interne_equipe',
        'Note interne (non publiée)',
        'juridique_afficher_metabox_note',
        'post',
        'side',
        'low'
    );
} );

function juridique_afficher_metabox_note( WP_Post $post ) {
    $note = get_post_meta( $post->ID, '_note_interne_equipe', true );

    wp_nonce_field( 'juridique_note_nonce', 'juridique_note_nonce_champ' );
    ?>
    <textarea name="note_interne_equipe" rows="4" style="width:100%;"><?php echo esc_textarea( $note ); ?></textarea>
    <p class="description">Visible uniquement par l'équipe éditoriale, jamais publiée.</p>
    <?php
}

add_action( 'save_post', function ( $post_id ) {
    if ( ! isset( $_POST['juridique_note_nonce_champ'] )
        || ! wp_verify_nonce( $_POST['juridique_note_nonce_champ'], 'juridique_note_nonce' )
        || ! current_user_can( 'edit_others_posts' ) ) {
        return;
    }

    update_post_meta(
        $post_id,
        '_note_interne_equipe',
        sanitize_textarea_field( $_POST['note_interne_equipe'] ?? '' )
    );
} );
```

Le préfixe `_` devant le nom de la meta (`_note_interne_equipe`) a aussi son utilité propre : WordPress masque par convention les meta dont le nom commence par un tiret bas dans l'éditeur de champs personnalisés classique, ce qui évite qu'elle apparaisse par erreur dans une interface non prévue pour elle.

### Fermer la porte du flux RSS

Un flux RSS n'inclut normalement pas les post meta, sauf si un thème ou une extension les y injecte explicitement via le hook `the_content_feed` ou un widget personnalisé. Le risque existe surtout si une extension tierce affiche « tous les champs personnalisés » sans distinction. Par précaution, on peut exclure explicitement cette meta de tout affichage de champs personnalisés génériques avec le filtre `is_protected_meta` :

```
add_filter( 'is_protected_meta', function ( $protegee, $meta_key ) {
    if ( '_note_interne_equipe' === $meta_key ) {
        return true;
    }

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

Une meta marquée comme protégée par ce filtre est automatiquement exclue de l'éditeur de champs personnalisés générique dans l'administration, en plus d'être un signal clair pour toute extension qui respecte cette convention.

## Vérifier l'export WXR

L'export intégré de WordPress (`Outils > Exporter`) inclut par défaut toutes les meta non protégées d'un article. Comme la meta est déjà préfixée d'un tiret bas et marquée protégée à l'étape précédente, elle est exclue automatiquement de cet export — un point à vérifier concrètement en générant un export test plutôt que de le supposer, les comportements ayant pu évoluer selon les versions.

## Ce qu'il ne faut jamais faire

- Ne jamais afficher cette meta via `the_content` ou un filtre de contenu, même conditionné par `is_user_logged_in()` : un cache de page pourrait figer l'affichage pour un visiteur non autorisé.
- Ne jamais exposer la note dans une recherche interne (`pre_get_posts` avec un `meta_query` qui inclurait son contenu dans les résultats affichés au public).
- Ne jamais compter uniquement sur la dissimulation dans l'interface : les vérifications de capacité côté serveur restent la seule vraie protection.

> Un principe que je rappelle à chaque équipe éditoriale qui demande ce type de champ : « non affiché dans le thème » n'est jamais une garantie de confidentialité à soi seul. La vraie protection vient toujours des vérifications de capacité côté serveur, sur chaque canal de sortie possible.

## Le bilan

Un champ interne bien conçu ne se limite pas à une métabox discrète : il faut penser explicitement à chaque canal par lequel WordPress pourrait l'exposer sans le vouloir — API REST, export, champs personnalisés génériques. Une fois ces trois portes fermées, la note reste ce qu'elle doit être : un espace de travail d'équipe, invisible du reste du monde.
