Skip to content

Tout pour WordPress, le développement web — et plus encore

🛠 Taxonomies exclusives dans WordPress : comment remplacer les cases à cocher par des boutons radio

🛠 Taxonomies exclusives dans WordPress : comment remplacer les cases à cocher par des boutons radio

Par défaut, WordPress vous permet d’attribuer à un article autant de termes d’une même taxonomie que vous le souhaitez. Des cases à cocher dans la barre latérale, et le tour est joué. Mais que faire si le client a besoin que l’éditeur sélectionne exactement une option? Par exemple, «Type de projet»: étude de cas, page d’atterrissage ou boutique en ligne. Trois options, et en cumuler deux n’a aucun sens.

Il n’existe pas de bouton «rendre la taxonomie exclusive» dans WordPress. Un ticket dans Trac est en attente depuis 2010 sans aucune avancée. Mais la tâche peut être résolue avec du code, sans extensions ni dépendances supplémentaires.

À la fin de cet article, vous aurez transformé la méta-boîte standard avec cases à cocher en un panneau avec boutons radio: exactement un terme par article, et moins d’erreurs de saisie.

💡 Aperçu rapide:

  • Enregistrez une taxonomie avec le paramètre meta_box_cb pour que la méta-boîte standard n’apparaisse pas.
  • Sur le hook add_meta_boxes, créez votre propre bloc avec des boutons radio.
  • Utilisez save_post pour écrire le terme sélectionné dans la base de données.
  • Le code complet peut être copié dans le fichier functions.php du thème enfant et fonctionne immédiatement.

À quoi servent les taxonomies et pourquoi l’exclusivité est importante

Une taxonomie dans WordPress est un mécanisme de regroupement des articles. Les «Catégories» et «Étiquettes» standard sont aussi des taxonomies. Une taxonomie personnalisée est créée pour une tâche spécifique: «Type de projet» pour un portfolio, «Région» pour un annuaire d’agences, «Type de service» pour une grille tarifaire.

Les catégories natives fonctionnent comme une taxonomie exclusive: un article appartient à exactement une catégorie, sauf si vous utilisez des extensions. La hiérarchie «parent → enfant» suggère à l’éditeur la logique de sélection.

Cependant, toute taxonomie personnalisée enregistrée via register_taxonomy() est non exclusive par défaut. L’interface se compose de cases à cocher ou d’un champ avec autocomplétion. Pour les étiquettes et les attributs de produit, c’est correct. Mais lorsque chaque article doit avoir exactement un terme, les cases à cocher deviennent une source d’erreurs.

La solution: masquer la méta-boîte standard et afficher la vôtre, avec des boutons radio et un contrôle strict. Ce n’est pas un contournement mais une API WordPress documentée, simplement répartie sur plusieurs étapes.

Étape 1: enregistrer une taxonomie personnalisée

La base est la fonction register_taxonomy(). Le code s’ajoute dans le functions.php du thème enfant ou via l’extension Code Snippets. Créons une taxonomie project_type pour les articles standard:

1function sd_register_project_type_taxonomy() {
2 register_taxonomy(
3 'project_type',
4 'post',
5 array(
6 'label' => __( 'Project Type', 'textdomain' ),
7 'public' => true,
8 'show_in_rest' => true,
9 'hierarchical' => true,
10 'show_in_quick_edit' => false,
11 'meta_box_cb' => false,
12 )
13 );
14}
15add_action( 'init', 'sd_register_project_type_taxonomy' );

Paramètres clés:

  • hierarchical => true active une structure arborescente, comme les catégories. Les termes sont organisés hiérarchiquement: «Design → Page d’atterrissage», «Développement → Boutique en ligne».
  • show_in_rest => true rend la taxonomie disponible dans l’API REST et l’éditeur de blocs. Sans cela, Gutenberg ne verra pas la méta-boîte.
  • meta_box_cb => false et show_in_quick_edit => false suppriment complètement l’interface standard de sélection des termes.

Après avoir sauvegardé le code, la taxonomie project_type est apparue dans le menu «Articles». Les termes s’ajoutent via «Articles → Type de projet» avec une interface standard, comme pour les catégories.

Étape 2: masquer la méta-boîte standard

Cette étape a en réalité déjà été réalisée avec les paramètres meta_box_cb et show_in_quick_edit de l’étape 1. Pour récapituler:

  • meta_box_cb => false supprime la méta-boîte de la page d’édition d’article.
  • show_in_quick_edit => false masque la taxonomie des panneaux d’édition rapide et d’édition groupée.

Sans eux, WordPress ajoute une interface par défaut: pour les taxonomies hiérarchiques, des cases à cocher de catégories; pour les non hiérarchiques, un champ d’étiquette avec autocomplétion.

Paramètres meta_box_cb et show_in_quick_edit dans register_taxonomy

Les termes sont renseignés via une page de gestion distincte:

Page de gestion des termes de taxonomie personnalisée dans l'administration WordPress

Étape 3: créer une méta-boîte personnalisée avec des boutons radio

Enregistrez votre propre méta-boîte via le hook add_meta_boxes. Ajoutez dans functions.php:

1add_action( 'add_meta_boxes', 'sd_add_project_type_meta_box' );
2
3function sd_add_project_type_meta_box() {
4 add_meta_box(
5 'project_type_box',
6 __( 'Project Type', 'textdomain' ),
7 'sd_render_project_type_meta_box',
8 'post',
9 'side',
10 'default'
11 );
12}

Paramètres de add_meta_box():

  • project_type_box: identifiant interne (arbitraire mais unique).
  • 'Project Type': titre dans le panneau d’administration.
  • sd_render_project_type_meta_box: fonction de rendu.
  • 'post': type d’article; peut être un tableau pour plusieurs CPT.
  • 'side': barre latérale. Alternatives: 'normal', 'advanced'.

La fonction qui affiche les boutons radio:

1function sd_render_project_type_meta_box( $post ) {
2 $terms = get_terms( array(
3 'taxonomy' => 'project_type',
4 'hide_empty' => false,
5 ) );
6
7 if ( empty( $terms ) || is_wp_error( $terms ) ) {
8 echo '<p>First, add terms on the “Project Type” page.</p>';
9 return;
10 }
11
12 $current_terms = get_the_terms( $post->ID, 'project_type' );
13 $current_id = ( ! empty( $current_terms ) && ! is_wp_error( $current_terms ) )
14 ? $current_terms[0]->term_id
15 : 0;
16
17 foreach ( $terms as $term ) : ?>
18 <label style="display:block;margin-bottom:4px;">
19 <input type="radio"
20 name="project_type_term"
21 value="<?php echo esc_attr( $term->term_id ); ?>"
22 <?php checked( $current_id, $term->term_id ); ?>>
23 <?php echo esc_html( $term->name ); ?>
24 </label>
25 <?php endforeach;
26}

Ce qui est important ici:

  • get_terms() avec hide_empty => false renvoie tous les termes, y compris ceux non utilisés.
  • get_the_terms() renvoie un tableau; nous prenons le premier élément [0] puisque la logique garantit au maximum un terme.
  • checked() est une fonction WordPress native qui produit checked="checked" en cas de correspondance.
  • esc_attr() et esc_html() sont des échappements obligatoires.

Le résultat est un bloc propre avec des boutons radio:

Boîte méta personnalisée avec boutons radio pour sélectionner un seul terme de taxonomie

Pas de cases à cocher, aucun moyen de sélectionner deux options.

Étape 4: enregistrer le terme lors de la sauvegarde de l’article

Sans cette étape, la méta-boîte est purement décorative. Nous utilisons le hook save_post:

1add_action( 'save_post', 'sd_save_project_type_term' );
2
3function sd_save_project_type_term( $post_id ) {
4 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
5 return;
6 }
7
8 if ( ! current_user_can( 'edit_post', $post_id ) ) {
9 return;
10 }
11
12 if ( isset( $_POST['project_type_term'] ) ) {
13 $term_id = absint( $_POST['project_type_term'] );
14 wp_set_object_terms( $post_id, $term_id, 'project_type' );
15 }
16}

Détails:

  • DOING_AUTOSAVE: nous ignorons les sauvegardes automatiques. Sans cette vérification, le terme est écrasé en arrière-plan toutes les 60 secondes.
  • current_user_can( 'edit_post', $post_id ): contrôle de permission de base.
  • absint() convertit la valeur en entier positif, plus sûr que (int) sanitize_text_field().
  • wp_set_object_terms() avec un seul ID (pas un tableau) écrit exactement un terme, en supprimant les associations précédentes.

Terminé. Sauvegardez l’article, et la sélection du bouton radio sera verrouillée. Lorsque vous le rouvrirez, le terme sélectionné sera mis en surbrillance.

Code complet à copier

Les quatre étapes en un seul extrait. Ajoutez-le au functions.php de votre thème enfant ou via Code Snippets:

1/**
2 * Exclusive taxonomy "Project Type" — one term per post.
3 * Add to child theme's functions.php.
4 */
5function sd_register_project_type_taxonomy() {
6 register_taxonomy(
7 'project_type',
8 'post',
9 array(
10 'label' => __( 'Project Type', 'textdomain' ),
11 'public' => true,
12 'show_in_rest' => true,
13 'hierarchical' => true,
14 'show_in_quick_edit' => false,
15 'meta_box_cb' => false,
16 )
17 );
18}
19add_action( 'init', 'sd_register_project_type_taxonomy' );
20
21add_action( 'add_meta_boxes', 'sd_add_project_type_meta_box' );
22
23function sd_add_project_type_meta_box() {
24 add_meta_box(
25 'project_type_box',
26 __( 'Project Type', 'textdomain' ),
27 'sd_render_project_type_meta_box',
28 'post',
29 'side',
30 'default'
31 );
32}
33
34function sd_render_project_type_meta_box( $post ) {
35 $terms = get_terms( array(
36 'taxonomy' => 'project_type',
37 'hide_empty' => false,
38 ) );
39
40 if ( empty( $terms ) || is_wp_error( $terms ) ) {
41 echo '<p>First, add terms on the “Project Type” page.</p>';
42 return;
43 }
44
45 $current_terms = get_the_terms( $post->ID, 'project_type' );
46 $current_id = ( ! empty( $current_terms ) && ! is_wp_error( $current_terms ) )
47 ? $current_terms[0]->term_id
48 : 0;
49
50 foreach ( $terms as $term ) : ?>
51 <label style="display:block;margin-bottom:4px;">
52 <input type="radio"
53 name="project_type_term"
54 value="<?php echo esc_attr( $term->term_id ); ?>"
55 <?php checked( $current_id, $term->term_id ); ?>>
56 <?php echo esc_html( $term->name ); ?>
57 </label>
58 <?php endforeach;
59}
60
61add_action( 'save_post', 'sd_save_project_type_term' );
62
63function sd_save_project_type_term( $post_id ) {
64 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
65 return;
66 }
67
68 if ( ! current_user_can( 'edit_post', $post_id ) ) {
69 return;
70 }
71
72 if ( isset( $_POST['project_type_term'] ) ) {
73 $term_id = absint( $_POST['project_type_term'] );
74 wp_set_object_terms( $post_id, $term_id, 'project_type' );
75 }
76}

⚠️ Faites une sauvegarde complète du site avant de coller. Le code a été testé sur la version actuelle de WordPress avec l’éditeur classique. Dans Gutenberg, la méta-boîte personnalisée s’affiche dans la barre latérale sans modification.

En pratique, nous avons déployé cet extrait sur trois projets, et il a fonctionné partout sans modifications. Si vous avez un type d’article hiérarchique ou plusieurs rôles d’éditeur, remplacez 'post' par votre slug et vérifiez les permissions dans save_post.


Le Trac de WordPress a un ticket #14877 ouvert depuis 2010 pour la prise en charge native des taxonomies exclusives. Dès qu’un paramètre 'exclusive' => true apparaîtra dans le cœur, toute cette construction se réduira à une seule ligne. Tant que le ticket n’avance pas, l’approche par boutons radio reste la solution principale.

Et ci-dessous, une courte vidéo sur le sujet pour que vous puissiez voir le processus en action:

⁉️🤔 Foire aux questions

Cela fonctionne-t-il dans Gutenberg?

Oui. Le paramètre show_in_rest => true lors de l’enregistrement de la taxonomie active la compatibilité avec l’éditeur de blocs. La méta-boîte personnalisée apparaît dans la barre latérale du document, et les boutons radio s’affichent et se sauvegardent correctement.

Cette approche peut-elle être appliquée aux types d’articles personnalisés?

Oui. Remplacez 'post' dans register_taxonomy() et add_meta_box() par le slug de votre CPT. Le reste du code (nom de la taxonomie, libellé, paramètres) reste identique. L’approche fonctionne avec tout type d’article enregistré, y compris ceux créés via ACF ou Custom Post Type UI.

Que se passe-t-il si l’éditeur ne sélectionne aucun terme?

L’article sera sauvegardé sans terme attribué; save_post n’appellera tout simplement pas wp_set_object_terms(). Si la sélection obligatoire est critique, ajoutez une validation JavaScript dans l’administration ou une vérification via le hook pre_post_update.

Pourquoi ne pas utiliser l’extension Radio Buttons for Taxonomies?

Vous pouvez. L’extension résout la tâche sans code et compte plus de 100 000 installations actives. L’inconvénient est une dépendance supplémentaire. Pour un ou deux sites, l’extension se justifie. Pour les agences et les multisites, le code dans le thème donne un contrôle total sans mises à jour ni conflits supplémentaires.

Comment ajouter une sélection hiérarchique (parent → enfant)?

Les taxonomies hiérarchiques (hierarchical => true) obtiennent automatiquement une structure parent-enfant. Pour afficher la hiérarchie dans la méta-boîte personnalisée, remplacez get_terms() par wp_dropdown_categories() en utilisant le paramètre 'taxonomy' => 'project_type'; la fonction produira une liste déroulante avec indentation.

En résumé: quand cela vaut-il la peine d’écrire du code

Une taxonomie exclusive n’est pas nécessaire pour chaque projet. Si les éditeurs comprennent la logique du site et ne font pas d’erreurs lors de la sélection, les cases à cocher standard suffisent. Mais lorsque le coût des erreurs est élevé (une page d’atterrissage dans le portfolio marquée par erreur à la fois comme «boutique en ligne» et «étude de cas»), une demi-heure de codage est rentabilisée par la propreté du contenu.

  • Si vous avez un seul site et pas de développeur, installez Radio Buttons for Taxonomies. Cela fonctionne sans code.
  • Si vous êtes une agence ou gérez un multisite, copiez le code ci-dessus dans votre thème de base. Moins d’extensions, moins de points de défaillance lors des mises à jour.
  • Si votre site fonctionne uniquement sous Gutenberg, demandez-vous si vous avez réellement besoin d’une taxonomie. Peut-être qu’un champ ACF avec des boutons radio suffit: moins d’entités, une administration plus rapide.

Commencez par un site de test. Enregistrez la taxonomie, ajoutez trois termes et créez un article; l’interface fonctionnera immédiatement. Écrivez dans les commentaires pour quelle tâche vous avez utilisé une taxonomie exclusive.