Créa-blog

#100JoursPourCoder
Projet Créa-code

Ressources pour développeur web

Théme de la semaine : PHP version 8.5

Coder un Custom Post Type WordPress : Tutoriel complet

⏱️ Temps de lecture estimé : 9 minutes
Accueil PHP 8 Coder un Custom Post Type WordPress : Tutoriel complet

Vous avez sans doute remarqué que WordPress, malgré sa simplicité légendaire, commence à montrer ses limites dès qu’on veut aller un peu plus loin qu’un simple blog. À ses débuts, WordPress ne proposait que deux types de contenu : les articles et les pages. C’était suffisant pour tenir un petit site personnel ou un blog de cuisine. Mais dès qu’on veut gérer, par exemple, un portfolio, des projets clients, des recettes ou des fiches produits, on se retrouve vite à bricoler. C’est à ce moment qu’un Custom Post Type devient utile !

Un outil fabuleux, souvent méconnu des débutants : le Custom Post Type, ou Type de contenu personnalisé. C’est lui qui permet de transformer WordPress en un véritable couteau suisse capable d’héberger n’importe quel type de contenu : films, formations, événements, tutoriels, projets… bref, tout ce que votre imagination peut produire.

Dans ce tutoriel complet, nous allons voir ensemble ce qu’est un Custom Post Type, pourquoi il est indispensable dès qu’on veut structurer un site professionnel, et surtout comment le créer, l’afficher et le personnaliser pas à pas. Vous n’aurez besoin que d’un peu de curiosité, d’un accès à votre thème WordPress et d’un éditeur de texte.

Comprendre ce qu’est un Custom Post Type

Avant de mettre les mains dans le code, prenons le temps de comprendre de quoi il s’agit. Dans WordPress, un Post Type est une catégorie de contenu. Par défaut, WordPress en propose plusieurs :

  • post : les articles classiques, ceux de votre blog.
  • page : les pages statiques, comme “Accueil” ou “Contact”.
  • attachment : les fichiers médias (images, PDF, vidéos…).
  • revision : les sauvegardes automatiques de vos contenus.
  • nav_menu_item : les éléments des menus.

Mais ces types ne couvrent pas tous les besoins. Imaginez que vous gériez un site de cinéma : il vous faudrait des fiches de films. Si vous les mettez dans des articles, elles se mélangeront avec les actualités du blog. Pas idéal.

C’est exactement pour ça qu’on crée un Custom Post Type (CPT). Il s’agit tout simplement d’un nouveau type de contenu, séparé des autres, avec son propre espace dans le tableau de bord et sa propre adresse sur votre site.

Par exemple :

  • film pour vos fiches de films,
  • chapitre pour vos leçons de tutoriels,
  • recette pour vos plats,
  • projet pour vos réalisations de portfolio.

Pourquoi créer un Custom Post Type ?

Au lieu de tout ranger dans le même tiroir, un CPT vous permet d’organiser proprement votre site. Prenons un exemple simple : un blog de développement web. Comme le Créa-blog par exemple.

Vous publiez des articles d’actualité (“Les nouveautés de PHP 8.5”, qui est un très bon article en toute objectivité) et des tutoriels longs découpés en chapitres (“Apprendre la POO en PHP”). Si vous mettez tout dans la catégorie “Articles”, vos chapitres et vos news vont se mélanger, rendant la navigation confuse.

En créant un CPT “chapitre”, vous aurez :

  • Un menu séparé dans le tableau de bord (“Chapitres”).
  • Des URL distinctes : votresite.fr/chapitres/introduction-au-html/.
  • La possibilité d’afficher ces contenus différemment de vos articles.
CPT WordPress

Et surtout, un jour, si vous souhaitez que votre moteur de recherche interne ou votre page d’accueil affiche aussi ces chapitres, il vous suffira d’une petite ligne de code.

C’est l’une des grandes forces de WordPress : tout est extensible. Le Custom Post Type, c’est un peu comme créer votre propre mini-application à l’intérieur de WordPress.

Préparer votre environnement

Avant d’écrire la première ligne, un petit conseil : ne touchez jamais au code du thème principal directement. Si vous mettez à jour votre thème, vos modifications disparaîtront.

Il existe deux options plus sûres :

  1. Créer un thème enfant : c’est une copie légère du thème principal, qui vous permet de modifier le code sans risque.
  2. Utiliser un plugin personnalisé : idéal si vous comptez déplacer vos CPT d’un site à un autre.

Pour ce tutoriel, restons simples et plaçons notre code dans le fichier functions.php du thème actif. Vous trouverez ce fichier dans le dossier :

wp-content/themes/nom-de-votre-theme/functions.php

Ouvrez-le dans votre éditeur favori, ou directement depuis le tableau de bord WordPress via Apparence → Éditeur de fichiers de thème.

Pour aller plus loin, consultez notre tutoriel complet : Coder un plugin WordPress.

Créer votre premier Custom Post Type

Commençons par le code. Nous allons créer un CPT, ou Custom Post Type, appelé “Chapitre”, parfait pour un blog d’apprentissage. Ajoutez ce code à la fin de votre functions.php :

function crea_register_chapitre_cpt() {
    $labels = array(
        'name' => 'Chapitres',
        'singular_name' => 'Chapitre',
        'add_new' => 'Ajouter un nouveau',
        'add_new_item' => 'Ajouter un nouveau chapitre',
        'edit_item' => 'Modifier le chapitre',
        'new_item' => 'Nouveau chapitre',
        'view_item' => 'Voir le chapitre',
        'search_items' => 'Rechercher un chapitre',
        'not_found' => 'Aucun chapitre trouvé',
        'menu_name' => 'Chapitres'
    );

    $args = array(
        'labels' => $labels,
        'public' => true,
        'has_archive' => true,
        'menu_position' => 5,
        'menu_icon' => 'dashicons-welcome-learn-more',
        'rewrite' => array('slug' => 'chapitres'),
        'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'comments')
    );

    register_post_type('chapitre', $args);
}
add_action('init', 'crea_register_chapitre_cpt');

Enregistrez, puis actualisez votre tableau de bord WordPress. Comme par magie, un nouveau menu “Chapitres” apparaît à gauche. Vous pouvez déjà créer vos premiers contenus !

Décortiquons ce code ensemble

Comprendre chaque partie du code est essentiel pour ne pas le recopier bêtement.

La fonction register_post_type() est au cœur du système. Elle prend deux paramètres :

  1. Le slug du type de contenu (ici chapitre), qui servira dans les URLs et les requêtes.
  2. Un tableau d’arguments ($args) qui décrit le comportement du CPT.

Regardons quelques clés importantes :

  • public : si true, votre contenu est accessible sur le site public et dans l’administration.
  • has_archive : crée une page d’archive (exemple : /chapitres/) listant tous vos chapitres.
  • menu_icon : l’icône qui s’affiche dans le menu WordPress (vous pouvez en trouver la liste sur le site officiel des “dashicons”).
  • rewrite : permet de personnaliser le slug de vos URL.
  • supports : détermine les fonctionnalités disponibles : titre, éditeur, image, extrait, etc.

Et le tableau $labels ? Il sert uniquement à définir les textes qui s’affichent dans l’administration. C’est purement cosmétique, mais ça améliore l’expérience utilisateur.

Tableau des arguments de register_post_type()

Clé ($args)Type attenduValeur par défautRôle / Explication
labelstringnom du typeNom général affiché dans l’administration. Exemple : “Chapitres”.
labelsarrayauto-généréTableau de libellés personnalisés pour les boutons, menus, etc. (ex. “Ajouter un nouveau Chapitre”, “Modifier le Chapitre”).
descriptionstringvideDescription interne du type de contenu (utile pour les devs).
publicboolfalseRend le CPT visible à la fois dans l’administration et sur le site public.
exclude_from_searchbooldépend de publicSi true, le CPT n’apparaît pas dans les résultats de recherche WordPress.
publicly_queryablebooldépend de publicSi true, le CPT peut être affiché via des URLs publiques (ex. /chapitres/mon-chapitre/).
show_uibooldépend de publicAffiche ou non le menu du CPT dans l’administration.
show_in_menubool / stringdépend de show_uiSi true, le CPT apparaît dans le menu principal de l’administration. Si vous indiquez le slug d’un autre menu, le CPT s’y intégrera.
show_in_nav_menusbooldépend de publicPermet d’utiliser les éléments de ce CPT dans les menus de navigation.
show_in_admin_barbooldépend de show_in_menuAffiche ou non un lien “+ Nouveau [CPT]” dans la barre d’administration.
show_in_restboolfalseActive la compatibilité avec l’éditeur de blocs (Gutenberg) et l’API REST. Indispensable pour les CPT modernes.
rest_basestringslug du CPTDéfinit le point de terminaison pour l’API REST. Exemple : wp-json/wp/v2/chapitres.
rest_namespacestringwp/v2Permet de changer le namespace utilisé pour l’API REST.
menu_positionintnullPosition du menu dans la colonne d’administration (5 = sous “Articles”, 10 = sous “Médias”, etc.).
menu_iconstringdashicons-admin-postIcône du menu (utilisez une Dashicon : dashicons-bookdashicons-admin-users, etc.).
capability_typestring / array‘post’Type de capacité utilisé pour le contrôle des rôles. Exemple : 'page' ou 'chapitre'.
capabilitiesarrayautoDéfinition complète des permissions personnalisées (rarement nécessaire pour un usage basique).
map_meta_capboolfalseSi true, WordPress mappe automatiquement les capacités pour ce CPT (utile pour la gestion fine des droits).
hierarchicalboolfalseSi true, le CPT peut avoir des parents/enfants (comme les pages).
supportsarray['title', 'editor']Définit les fonctionnalités disponibles : titre, éditeur, image à la une, auteur, extrait, commentaires, etc.
register_meta_box_cbcallbacknullFonction de rappel pour ajouter des meta boxes personnalisées.
taxonomiesarrayvideListe des taxonomies (catégories, étiquettes, ou personnalisées) à associer à ce CPT.
has_archivebool / stringfalseSi true, crée une page d’archive (/chapitres/). Vous pouvez aussi indiquer un slug personnalisé.
rewritebool / arraytrueGère la réécriture d’URL : slug, pagination, etc. Exemple : ['slug' => 'chapitres', 'with_front' => false].
query_varbool / stringslug du CPTPermet de requêter le CPT via ?chapitre=nom. Si false, cette méthode est désactivée.
can_exportbooltruePermet ou non d’exporter les contenus du CPT avec l’outil d’export WordPress.
delete_with_userboolnullSi true, supprime les contenus du CPT lorsqu’un utilisateur est supprimé.
templatearray[]Définit un modèle de blocs prédéfini pour Gutenberg (liste d’arrangements de blocs à insérer automatiquement).
template_lockstring / boolfalseSi true ou 'all', empêche de modifier ou supprimer les blocs du modèle.
_builtinboolfalseRéservé à WordPress (ne pas toucher). Indique si le type est natif (postpage, etc.).
show_in_quick_editbooltruePermet d’afficher le CPT dans la modification rapide du tableau d’administration.
show_in_graphqlboolfalse(WPGraphQL) Active le support de ce CPT dans les requêtes GraphQL.
graphql_single_namestringNom singulier du CPT dans les requêtes GraphQL.
graphql_plural_namestringNom pluriel du CPT dans les requêtes GraphQL.

Exemple d’utilisation pratique avec plusieurs arguments

Voici un exemple complet et commenté reprenant plusieurs de ces paramètres :

function crea_register_projet_cpt() {
    $args = array(
        'label' => 'Projets',
        'description' => 'Liste des projets réalisés pour mes clients',
        'public' => true,
        'show_in_rest' => true,
        'menu_position' => 5,
        'menu_icon' => 'dashicons-portfolio',
        'has_archive' => true,
        'rewrite' => array('slug' => 'projets', 'with_front' => false),
        'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
        'taxonomies' => array('category', 'post_tag'),
        'hierarchical' => false,
        'show_in_nav_menus' => true,
        'show_in_admin_bar' => true,
        'can_export' => true,
    );
    register_post_type('projet', $args);
}
add_action('init', 'crea_register_projet_cpt');

Ce code crée un type de contenu “Projets” parfaitement intégré à WordPress, visible dans Gutenberg, avec archive, taxonomies, et icône dédiée.

Afficher votre CPT sur votre site WordPress

Créer le contenu, c’est bien. L’afficher, c’est mieux ! Par défaut, WordPress ne sait pas comment afficher un CPT. Il cherche un modèle (template) dans votre thème, selon une hiérarchie bien précise.

Formation web et informatique - Alban Guillier - Formateur

Des formations informatique pour tous !

Débutant ou curieux ? Apprenez le développement web, le référencement, le webmarketing, la bureautique, à maîtriser vos appareils Apple et bien plus encore…

Formateur indépendant, professionnel du web depuis 2006, je vous accompagne pas à pas et en cours particulier, que vous soyez débutant ou que vous souhaitiez progresser. En visio, à votre rythme, et toujours avec pédagogie.

Découvrez mes formations Qui suis-je ?

Pour notre chapitre, WordPress va d’abord chercher :

  1. single-chapitre.php (pour les pages individuelles)
  2. archive-chapitre.php (pour la liste complète)
  3. À défaut, il utilisera single.php ou archive.php.

Si vous souhaitez personnaliser l’affichage, copiez single.php, renommez-le en single-chapitre.php, puis modifiez-le selon vos besoins. Attention, single.php doit toujours exister ! Il faut simplement le dupliquer et renommer sa copie.

Par exemple, vous pouvez ajouter un encart “Chapitre précédent / Chapitre suivant” pour créer une navigation linéaire.

<?php
the_post_navigation(array(
    'prev_text' => '← Chapitre précédent : %title',
    'next_text' => 'Chapitre suivant : %title →',
));
?>

Petit conseil : n’oubliez pas de rafraîchir les permaliens (Réglages → Permaliens → Enregistrer). Sans cela, vos nouvelles URL peuvent retourner une erreur 404.

Ajouter des taxonomies à votre CPT

Les taxonomies permettent de classer vos contenus, un peu comme les catégories et les étiquettes pour les articles. Vous pouvez créer vos propres taxonomies pour vos chapitres.

Par exemple, ajoutons une taxonomie “Langage” (HTML, CSS, JS…) à nos chapitres :

function crea_register_chapitre_taxonomy() {
    register_taxonomy(
        'langage',
        'chapitre',
        array(
            'label' => 'Langages',
            'rewrite' => array('slug' => 'langages'),
            'hierarchical' => true,
        )
    );
}
add_action('init', 'crea_register_chapitre_taxonomy');

Désormais, dans le menu “Chapitres”, vous verrez une colonne “Langages”.
Vous pouvez assigner un langage à chaque chapitre pour les trier ou les filtrer.

Afficher vos Custom Post Type sur la page d’accueil

Vous voulez que vos chapitres apparaissent aux côtés de vos articles sur la page d’accueil ? C’est possible en quelques lignes. Ajoutez cette fonction à votre functions.php :

function crea_include_chapitres_in_home($query) {
    if ($query->is_home() && $query->is_main_query()) {
        $query->set('post_type', array('post', 'chapitre'));
    }
}
add_action('pre_get_posts', 'crea_include_chapitres_in_home');

Cette petite fonction modifie la requête principale de la page d’accueil pour inclure à la fois les articles (post) et les chapitres (chapitre). Enregistrez, rafraîchissez, et vos chapitres s’afficheront comme s’ils faisaient partie du blog.

Créer un CPT sans code : les plugins

Si le code vous effraie encore un peu, sachez qu’il existe des plugins gratuits pour créer vos CPT sans écrire une ligne. Les plus connus sont :

  • Custom Post Type UI
  • Pods
  • JetEngine (plus complet, mais souvent payant)

Ils offrent une interface graphique où vous pouvez définir vos labels, slug, taxonomies, et options d’affichage. C’est parfait pour les débutants ou les projets où le code n’est pas accessible.

Mais gardez en tête qu’apprendre à le faire vous-même, c’est comme apprendre à conduire une voiture au lieu d’utiliser un taxi. Vous gagnez en liberté et en compréhension.

Ajouter des champs personnalisés (Custom Fields)

Les CPT deviennent encore plus puissants quand on leur ajoute des champs personnalisés. Imaginez un CPT “Film” avec des champs comme “Réalisateur”, “Durée”, “Année de sortie”. Pour cela, deux options :

  1. Utiliser le plugin Advanced Custom Fields (ACF), qui ajoute des champs via une interface simple.
  2. Ou le faire en code pur, avec add_meta_box() et get_post_meta().

Voici un petit exemple :

function crea_add_duree_field() {
    add_meta_box(
        'chapitre_duree',
        'Durée du chapitre',
        'crea_render_duree_field',
        'chapitre',
        'side'
    );
}
add_action('add_meta_boxes', 'crea_add_duree_field');

function crea_render_duree_field($post) {
    $value = get_post_meta($post->ID, '_chapitre_duree', true);
    echo '<input type="text" name="chapitre_duree" value="' . esc_attr($value) . '" />';
}

function crea_save_duree_field($post_id) {
    if (array_key_exists('chapitre_duree', $_POST)) {
        update_post_meta(
            $post_id,
            '_chapitre_duree',
            sanitize_text_field($_POST['chapitre_duree'])
        );
    }
}
add_action('save_post', 'crea_save_duree_field');

Une fois ce code ajouté, vous verrez une nouvelle boîte “Durée du chapitre” dans votre éditeur.

Exemple concret : un site de recettes

Pour illustrer, imaginez un blog de cuisine. Vous créez un CPT “Recette” avec des champs “Ingrédients”, “Temps de cuisson”, “Difficulté”. Chaque recette a sa propre page, et une archive affiche toutes vos recettes.

Grâce aux taxonomies, vous pouvez même trier par type de plat : entrée, plat, dessert. Résultat : votre site devient clair, structuré et facile à explorer.

Vous ne publiez plus des articles “fourre-tout”, mais de véritables fiches thématiques bien classées.

Erreurs fréquentes à éviter

Beaucoup de débutants tombent dans les mêmes pièges :

  • Oublier de rafraîchir les permaliens après avoir créé le CPT, ce qui provoque des erreurs 404.
  • Ne pas créer de modèles (templates) dédiés, laissant WordPress afficher le contenu par défaut.
  • Mélanger des slug identiques entre taxonomies et CPT (par exemple /chapitres/ pour les deux).
  • Oublier de sauvegarder le site avant de modifier le fichier functions.php.

Soyez méthodique : testez une étape à la fois et vérifiez toujours le résultat sur votre site.


Créer un Custom Post Type dans WordPress n’a rien de sorcier. C’est un outil incroyablement puissant pour tous ceux qui veulent transformer leur site en véritable plateforme professionnelle. Vous partez d’un simple blog, et en quelques lignes de code, vous pouvez créer un espace pour vos tutoriels, vos projets, vos recettes ou vos événements.

Au-delà de la technique, ce qu’il faut retenir, c’est que le CPT vous rend libre. Libre d’organiser votre contenu comme vous le souhaitez, libre de créer vos propres structures, libre de donner à votre site la forme qui correspond à votre vision.

Et si vous débutez, prenez le temps d’expérimenter. C’est en essayant que vous comprendrez réellement comment fonctionne WordPress. Comme dans la cuisine : on peut lire mille recettes, mais c’est en mettant la main à la pâte qu’on apprend à doser les ingrédients.

Alors, à vous de jouer : créez votre premier Custom Post Type, testez-le, personnalisez-le, et amusez-vous à bâtir un WordPress à votre image.