vendredi 25 septembre 2026

À propos

Contact

Extensions

Custom Post Types et taxonomies personnalisées : le guide complet

register_post_type et register_taxonomy en détail : arguments essentiels, liaison entre types, réécriture d'URL et erreurs qui cassent les permaliens.

Par Clément Hadrot • 30 novembre 2020 • 5 min de lecture • Aucun commentaire
Custom Post Types et taxonomies personnalisées : le guide complet pour extensions

Créer un type de contenu personnalisé est souvent la toute première fonctionnalité qu’un développeur WordPress apprend à coder. C’est aussi l’une des rares fonctions dont la signature complète — plus de trente arguments possibles — n’est presque jamais explorée dans son intégralité, alors que plusieurs de ces arguments conditionnent le comportement de l’extension pendant des années.

Cet article détaille les arguments qui comptent vraiment pour register_post_type() et register_taxonomy(), ainsi que les erreurs classiques : permaliens cassés après une modification de slug, type de contenu absent de l’éditeur de blocs, ou taxonomie invisible dans les résultats de recherche.

Un register_post_type qui pense à tout

add_action( 'init', function () {
    register_post_type( 'produit', [
        'labels'              => [
            'name'          => __( 'Produits', 'acme' ),
            'singular_name' => __( 'Produit', 'acme' ),
            'add_new_item'  => __( 'Ajouter un produit', 'acme' ),
        ],
        'public'              => true,
        'show_in_rest'        => true,
        'rest_base'           => 'produits',
        'has_archive'         => true,
        'menu_icon'           => 'dashicons-cart',
        'supports'            => [ 'title', 'editor', 'thumbnail', 'custom-fields' ],
        'rewrite'             => [ 'slug' => 'produit', 'with_front' => false ],
        'capability_type'     => 'post',
        'map_meta_cap'        => true,
    ] );
} );

Trois arguments méritent une attention particulière :

  • show_in_rest à true est obligatoire pour que le type de contenu apparaisse dans l’éditeur de blocs (Gutenberg) et soit accessible via l’API REST. Un oubli fréquent chez les développeurs venus de l’époque de l’éditeur classique.
  • rewrite.with_front évite que le slug soit préfixé par le chemin défini dans les réglages de permaliens (souvent utile si ce chemin contient déjà un segment de type /blog/).
  • map_meta_cap à true avec capability_type personnalisé permet d’utiliser des capabilities fines (edit_produit, delete_produits) plutôt que les capabilities génériques edit_post, ce qui devient indispensable dès qu’un rôle personnalisé doit avoir des droits différenciés.

Le piège des permaliens après activation

WordPress construit ses règles de réécriture d’URL une seule fois et les met en cache dans la table d’options. Un type de contenu ajouté par une extension fraîchement activée ne fonctionnera pas tant que ce cache n’est pas régénéré, provoquant une page 404 sur toutes les URL de ce type. La solution : déclencher flush_rewrite_rules() au moment de l’activation, jamais à chaque chargement (ce qui dégraderait sérieusement les performances).

register_activation_hook( __FILE__, function () {
    // Il faut d'abord enregistrer le CPT, sinon ses règles ne sont pas connues
    acme_enregistrer_produit();
    flush_rewrite_rules();
} );

register_deactivation_hook( __FILE__, function () {
    flush_rewrite_rules();
} );

Un appel à flush_rewrite_rules() dans le hook init lui-même, directement dans le corps de l’extension, est une erreur de débutant très répandue : elle reconstruit les règles à chaque chargement de page, ce qui peut ajouter plusieurs dizaines de millisecondes à chaque requête sur un site avec beaucoup de contenu.

L'essentiel à retenir : register_post_type() prend plus de 30 arguments ; Toujours flusher les règles de réécriture à l'activation ; show_in_rest indispensable pour l'éditeur de blocs

Taxonomies : hiérarchiques ou non, et leur liaison

Une taxonomie hiérarchique (comme les catégories) autorise des relations parent-enfant et affiche une case à cocher dans l’administration. Une taxonomie non hiérarchique (comme les étiquettes) affiche un champ de saisie libre avec autocomplétion.

add_action( 'init', function () {
    register_taxonomy( 'gamme_produit', 'produit', [
        'labels'            => [
            'name'          => __( 'Gammes', 'acme' ),
            'singular_name' => __( 'Gamme', 'acme' ),
        ],
        'hierarchical'      => true,
        'show_in_rest'      => true,
        'show_admin_column' => true,
        'rewrite'           => [ 'slug' => 'gamme' ],
    ] );
} );

show_admin_column ajoute une colonne dans la liste des articles pour visualiser rapidement les termes associés, un détail d’ergonomie souvent négligé mais très apprécié par les équipes éditoriales.

Lier plusieurs types de contenu à une même taxonomie

Une taxonomie peut s’appliquer à plusieurs types de contenu en passant un tableau plutôt qu’une chaîne :

register_taxonomy( 'gamme_produit', [ 'produit', 'accessoire' ], [ /* ... */ ] );

// Ou, après coup, pour un type déjà enregistré ailleurs :
register_taxonomy_for_object_type( 'gamme_produit', 'accessoire' );

Cette dernière fonction est particulièrement utile lorsque l’extension doit rattacher une de ses taxonomies à un type de contenu déclaré par une autre extension, sans en modifier le code source.

Vérifier que la recherche native fonctionne

Un CPT avec public à false n’apparaît jamais dans les résultats de recherche native, quel que soit le réglage exclude_from_search. À l’inverse, un CPT interne (des données techniques, par exemple des journaux d’activité) doit explicitement passer exclude_from_search à true même avec public à false, car certains thèmes personnalisent la requête de recherche et peuvent malgré tout l’inclure.

Un CPT mal pensé dès le départ — sans REST, sans capabilities dédiées, sans slug réfléchi — coûte cher à corriger une fois que des milliers de contenus ont été publiés avec. Mieux vaut passer une heure de plus à la conception qu’une journée de migration six mois plus tard.

Désenregistrer proprement à la désactivation

Contrairement à une idée reçue, il n’est pas nécessaire d’appeler unregister_post_type() à la désactivation d’une extension : WordPress ne conserve pas les types de contenu en mémoire entre les requêtes. Ce qui compte, c’est de régénérer les règles de réécriture pour que les URL du CPT désactivé ne renvoient plus une page blanche mais une 404 propre.

En résumé

Un register_post_type() ou register_taxonomy() bien pensé anticipe l’intégration avec l’éditeur de blocs, la recherche, les permaliens et les capabilities. Ces arguments coûtent quelques minutes à documenter au moment de la conception et évitent des refontes douloureuses une fois le contenu en production.

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