Chapitre 7.4 — Métadonnées & metaboxes
⏱️ TL;DR — Les métadonnées (
post_meta) attachent des données custom à un contenu (ISBN, prix, date d’un événement…). On les lit/écrit avecget_post_meta()/update_post_meta(). Deux façons de les éditer : les metaboxes classiques (un panneau PHP sur l’écran d’édition, avec nonce + sanitize + capability) ou, mieux à l’ère Gutenberg, les meta enregistrées (register_post_meta()avecshow_in_rest) éditées via un panneau de bloc React (Partie 8). La règle de sécurité est omniprésente : vérifier le nonce, la capability, et assainir avant d’enregistrer.
🎯 Objectifs
- Lire/écrire des métadonnées avec les fonctions dédiées.
- Créer une metabox classique sécurisée (nonce, sanitize, capability).
- Enregistrer une meta pour la REST/Gutenberg (
register_post_meta). - Comprendre
_underscore(meta protégée) et le pont vers le panneau bloc.
1. Lire et écrire une métadonnée
// Écrire
update_post_meta( $post_id, 'wpr_isbn', '978-2-07-036002-4' );
// Lire (true = valeur unique, pas un tableau)
$isbn = get_post_meta( $post_id, 'wpr_isbn', true );
// Supprimer
delete_post_meta( $post_id, 'wpr_isbn' );- Stockées dans
wp_postmeta(ch. 4.6), modèle clé/valeur. - Le 3ᵉ argument
truedeget_post_metarenvoie une valeur (sinon un tableau de toutes les valeurs de cette clé).
Convention _underscore : une clé commençant par _ (ex. _wpr_prix) est protégée — elle n’apparaît pas dans la métabox générique « Champs personnalisés » et n’est pas éditable directement par l’utilisateur. On l’utilise pour les meta gérées par le code (via metabox/bloc dédié).
2. Une metabox classique (sécurisée)
Trois étapes : ajouter la metabox, l’afficher, enregistrer ses données à save_post.
// 1) Ajouter la metabox
add_action( 'add_meta_boxes', function () {
add_meta_box(
'wpr_book_details',
__( 'Détails du livre', 'wpr-books' ),
'wpr_book_details_html',
'livre', // écran (CPT)
'side' // contexte : side | normal | advanced
);
} );
// 2) Afficher le champ (+ NONCE)
function wpr_book_details_html( $post ) {
wp_nonce_field( 'wpr_book_save', 'wpr_book_nonce' ); // ⚠️ jeton anti-CSRF
$isbn = get_post_meta( $post->ID, '_wpr_isbn', true );
?>
<label for="wpr_isbn"><?php esc_html_e( 'ISBN', 'wpr-books' ); ?></label>
<input type="text" id="wpr_isbn" name="wpr_isbn"
value="<?php echo esc_attr( $isbn ); ?>" class="widefat" />
<?php
}
// 3) Enregistrer (nonce → capability → sanitize → update)
add_action( 'save_post_livre', function ( $post_id ) {
// a) Nonce (le formulaire vient bien de nous)
if ( ! isset( $_POST['wpr_book_nonce'] )
|| ! wp_verify_nonce( $_POST['wpr_book_nonce'], 'wpr_book_save' ) ) {
return;
}
// b) Éviter l'autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// c) Capability (droit d'éditer CE contenu)
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
// d) Sanitize AVANT d'enregistrer
if ( isset( $_POST['wpr_isbn'] ) ) {
update_post_meta( $post_id, '_wpr_isbn', sanitize_text_field( wp_unslash( $_POST['wpr_isbn'] ) ) );
}
} );⚠️ Piège critique — les 4 gardes de
save_post. À l’enregistrement d’une metabox, il faut toujours : (1) vérifier le nonce (wp_verify_nonce), (2) ignorer l’autosave (DOING_AUTOSAVE), (3) vérifier la capability (current_user_can('edit_post', $id)), (4) assainir l’entrée (sanitize_*+wp_unslash). Oublier l’un de ces gardes est une faille classique (CSRF, injection, écrasement pendant l’autosave). C’est le patron à mémoriser (approfondi ch. 7.7).
3. L’approche moderne : register_post_meta + REST
Pour l’ère Gutenberg/headless, on enregistre la meta pour qu’elle soit exposée en REST et éditable via un panneau de bloc React (Partie 8) :
add_action( 'init', function () {
register_post_meta( 'livre', 'wpr_isbn', array(
'type' => 'string',
'single' => true,
'show_in_rest' => true, // exposée dans /wp-json + éditable via @wordpress/data
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function () { return current_user_can( 'edit_posts' ); },
) );
} );Avantages :
- la meta apparaît dans la REST API (
/wp/v2/livre/{id}→meta.wpr_isbn) → headless direct (Partie 9) ; - elle est éditable proprement dans l’éditeur via
@wordpress/data/useEntityProp(Partie 8), sans metabox PHP ; sanitize_callbacketauth_callbackcentralisent la sécurité.
⚠️ Piège — meta non exposée en REST. Une meta non enregistrée (
register_post_meta) avecshow_in_restn’est pas visible dans la REST API (par défaut, les meta sont privées). Pour du headless ou un panneau bloc, enregistrez-la avecshow_in_rest => true. Attention : n’exposez pas de meta sensible (données internes) en REST sans réfléchir.
💡 Pour un dev React — Deux mondes : la metabox classique (formulaire PHP + POST +
save_post) est l’ancien modèle « form submit serveur ».register_post_meta+ panneau bloc est le modèle moderne : la meta devient un champ d’API que votre composant React lit/écrit via un store (useEntityProp), avec sauvegarde AJAX transparente — exactement votre façon de gérer un champ contrôlé relié à une API. Pour un CPT destiné au headless, privilégiez cette voie.
4. Champs multiples et validation
- Pour plusieurs champs, répétez le patron (un nonce par metabox suffit) ; assainissez chaque champ selon son type (
sanitize_text_field,absint,sanitize_email,esc_url_raw…). - Pour de la validation métier (ISBN valide, prix positif), validez avant
update_post_metaet signalez l’erreur (transient d’admin notice, ou côté bloc). - Pour des structures complexes (répétables), envisagez une table custom (ch. 5.6) ou un champ JSON — mais le plus souvent,
post_metasuffit.
✏️ Exercices
- Citez les quatre vérifications obligatoires avant d’enregistrer une meta dans
save_post. - Vous développez un CPT destiné à être consommé par une app Next.js. Metabox classique ou
register_post_meta? Pourquoi ? - Pourquoi préfixer certaines clés meta avec
_(underscore) ?
✅ Solution
- (1) Vérifier le nonce (
wp_verify_nonce), (2) ignorer l’autosave (DOING_AUTOSAVE), (3) vérifier la capability (current_user_can('edit_post', $id)), (4) assainir l’entrée (sanitize_*+wp_unslash). register_post_metaavecshow_in_rest => true: la meta est exposée dans la REST API (donc lisible/éditable par le front Next.js et par un panneau bloc React), avec sanitize/auth centralisés. Une metabox classique n’exposerait pas la donnée en REST.- Le préfixe
_rend la meta protégée : elle n’apparaît pas dans la métabox générique « Champs personnalisés » et n’est pas éditable directement par l’utilisateur — réservée à une gestion par le code.
🧠 Quiz de révision
1. Quelles fonctions lisent/écrivent une métadonnée ?
get_post_meta() et update_post_meta() (+ delete_post_meta).
2. Que doit contenir une metabox pour être sûre à l’enregistrement ?
Un nonce (formulaire), et à save_post : vérif nonce + autosave + capability + sanitize.
3. Comment exposer une meta en REST / à Gutenberg ?
Avec register_post_meta() et show_in_rest => true (+ sanitize_callback, auth_callback).
4. Que signifie une clé meta commençant par _ ?
Une meta protégée, gérée par le code, invisible dans la métabox « Champs personnalisés ».
5. Pour un CPT headless, quelle approche de meta privilégier ?
register_post_meta avec show_in_rest (champ d’API éditable via @wordpress/data), plutôt qu’une metabox PHP.
Chapitre suivant : Settings API & pages d’administration.