
🔧 Comment créer un template pour un type de publication personnalisé dans WordPress
Vous avez ajouté un type de publication personnalisé sur votre site, par exemple «Promotions», «Portfolio» ou «Témoignages». Tout fonctionne: les publications sont créées, les champs meta sont remplis. Mais lorsque vous ouvrez l’une de ces publications en front-end, elle ressemble à un article de blog classique. Même mise en page, mêmes barres latérales, aucune différence. Pourtant, vous avez créé un type de publication personnalisé précisément pour que le contenu soit présenté différemment.
Le problème vient du fait que WordPress affiche par défaut toute publication personnalisée via single.php, le template universel pour toutes les publications uniques. Pour obtenir une mise en page spécifique à un type donné, vous avez besoin de votre propre fichier de template. Et cela s’avère étonnamment simple.
Voici un découpage étape par étape: de la hiérarchie des templates à deux méthodes de création (via un fichier de thème et via le filtre template_include), avec des exemples de code fonctionnels.
💡 Aperçu rapide:
- Comprendre comment WordPress cherche un template pour un type de publication personnalisé, et la priorité de
single-{post_type}.php - Copier le
single.phpde votre thème, le renommer pour votre CPT et le personnaliser - Explorer une méthode alternative via le filtre
template_include(pratique si vous ne voulez pas toucher au thème) - Créer le type de publication personnalisé lui-même avec l’extension Custom Post Type UI, rapidement et sans code
1. Comment WordPress choisit un template pour un type de publication personnalisé
La hiérarchie des templates de WordPress est une chaîne de fichiers que le cœur vérifie pour trouver le bon template pour afficher une page. Pour les publications standard, la chaîne est longue: single-post.php → single.php → singular.php → index.php. Pour les types de publication personnalisés, elle est plus courte, mais la logique est la même.
Lorsqu’un visiteur ouvre une publication personnalisée de type aktsii, WordPress vérifie les fichiers dans cet ordre:
single-aktsii.php, le template spécifique à ce type de publication personnalisésingle.php, le template générique pour une publication uniquesingular.php, le template pour tout contenu singulier (article, page, CPT)index.php, le dernier recours
Le premier fichier trouvé dans la chaîne est celui utilisé pour l’affichage. Si single-aktsii.php existe, WordPress le prend et s’arrête. S’il n’est pas trouvé, le cœur passe à single.php. C’est exactement la raison pour laquelle votre type de publication personnalisé ressemble à un article classique: il n’y a pas de fichier single-aktsii.php, donc le cœur se replie sur le single.php générique.
La solution en découle directement: créez single-{post_type}.php, et WordPress le prend automatiquement.
2. Créer un fichier de template: copier single.php et le renommer
C’est l’approche la plus simple et la plus fiable. Elle fonctionne avec n’importe quel thème classique et ne nécessite ni extension ni filtre.
Étape 1: trouvez le single.php de votre thème. Il se trouve à la racine du dossier du thème: /wp-content/themes/your-theme/single.php. Si le thème utilise le FSE (Full Site Editing) et est construit sur des blocs, ce fichier peut ne pas exister, et la méthode par filtre (template_include) sera plus pratique (section 4).
Étape 2: copiez et renommez. Copiez single.php et nommez-le selon le modèle single-{slug}.php: remplacez {slug} par le slug de votre type de publication personnalisé (celui spécifié lors de l’enregistrement, en caractères latins). Par exemple, pour un type avec le slug aktsii:
1 single-aktsii.php
Pour un type avec le slug portfolio, le fichier serait nommé single-portfolio.php. Pour testimonials, il devient single-testimonials.php. Important: le slug doit correspondre à celui spécifié dans le paramètre 'rewrite' => array('slug' => '...') lors de l’enregistrement.
Étape 3: replacez le fichier dans le dossier du thème. WordPress le prendra automatiquement pour toutes les publications de ce type. Aucune configuration supplémentaire n’est nécessaire; la hiérarchie des templates le gère automatiquement.
Étape 4: vérifiez. Ouvrez n’importe quelle publication du type personnalisé en front-end. Si vous voyez la même page qu’avant, vérifiez le nom du fichier (sensibilité à la casse, tirets au lieu de underscores) et videz le cache. Si le fichier a été créé dans un thème enfant et que le thème parent contient également single-{post_type}.php, le thème enfant est prioritaire.
3. Personnaliser le contenu du template
Le single.php copié est toujours identique à l’original; il affiche simplement la même mise en page générique. Nous allons maintenant le remplir avec du contenu spécifique au type de publication personnalisé.
3.1. Structure de base: afficher les champs personnalisés
Supposons que le type de publication personnalisé aktsii ait les champs aktsiya_data_start, aktsiya_data_end et aktsiya_skidka (créés via ACF, Meta Box ou manuellement). Voici un template minimal qui les affiche:
1 <?php 2 /** 3 * Template for custom type "Promotions" (single-aktsii.php) 4 */ 5 6 get_header(); 7 ?> 8 9 <main id="main" class="site-main" role="main"> 10 11 <?php while ( have_posts() ) : the_post(); ?> 12 13 <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 14 15 <header class="entry-header"> 16 <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?> 17 </header> 18 19 <?php if ( has_post_thumbnail() ) : ?> 20 <div class="post-thumbnail"> 21 <?php the_post_thumbnail( 'large' ); ?> 22 </div> 23 <?php endif; ?> 24 25 <div class="entry-content"> 26 <?php the_content(); ?> 27 28 <div class="custom-fields"> 29 <?php 30 $data_start = get_post_meta( get_the_ID(), 'aktsiya_data_start', true ); 31 $data_end = get_post_meta( get_the_ID(), 'aktsiya_data_end', true ); 32 $skidka = get_post_meta( get_the_ID(), 'aktsiya_skidka', true ); 33 34 if ( $data_start ) { 35 echo '<p><strong>Start Date:</strong> ' . esc_html( $data_start ) . '</p>'; 36 } 37 if ( $data_end ) { 38 echo '<p><strong>End Date:</strong> ' . esc_html( $data_end ) . '</p>'; 39 } 40 if ( $skidka ) { 41 echo '<p><strong>Discount:</strong> ' . esc_html( $skidka ) . '%</p>'; 42 } 43 ?> 44 </div> 45 </div> 46 47 </article> 48 49 <?php 50 if ( comments_open() || get_comments_number() ) : 51 comments_template(); 52 endif; 53 ?> 54 55 <?php endwhile; ?> 56 57 </main> 58 59 <?php 60 get_sidebar(); 61 get_footer();
C’est un template entièrement fonctionnel que vous pouvez déposer tel quel dans votre thème. Il affiche le titre, l’image mise en avant, le contenu et trois champs personnalisés dans un bloc séparé.
3.2. Ce que vous pouvez faire d’autre avec le template
À partir de là, les possibilités de personnalisation sont pratiquement illimitées:
- Supprimer la barre latérale: supprimez simplement l’appel à
get_sidebar(). - Changer l’enveloppe HTML: remplacez
<article>par un<div>portant la classe dont vous avez besoin, ajoutez votre propre grille. - Appeler une partie de template spécifique: par exemple,
get_template_part( 'template-parts/content', 'aktsii' )et conservez la logique dans un fichier séparé. - Charger des styles personnalisés: via
wp_enqueue_style()dansfunctions.phpavec une vérificationis_singular( 'aktsii' ).
Une remarque importante: si le thème est mis à jour, un fichier dans le thème parent peut être écrasé. Travaillez donc soit dans un thème enfant, soit utilisez la méthode par filtre de la section suivante.
4. Approche alternative: le filtre template_include
Si vous préférez ne pas modifier les fichiers du thème (ou si le thème est basé sur des blocs et ne possède pas de single.php classique), vous pouvez assigner un template via le hook template_include. Il se déclenche avant que WordPress n’inclue le fichier de template et vous permet de surcharger le chemin.
Inconvénient: vous devrez stocker le fichier de template soit dans une extension, soit dans un thème enfant, et le code doit pointer vers le bon chemin. Avantage: la logique n’est pas perdue lors de la mise à jour du thème parent.
4.1. Exemple: un CPT, un template
Ajoutez ceci au functions.php du thème enfant (ou à un MU-plugin):
1 add_filter( 'template_include', 'techblog_cpt_template', 99 ); 2 3 function techblog_cpt_template( $template ) { 4 if ( is_singular( 'aktsii' ) ) { 5 $custom_template = get_stylesheet_directory() . '/single-aktsii.php'; 6 if ( file_exists( $custom_template ) ) { 7 return $custom_template; 8 } 9 } 10 return $template; 11 }
Le code vérifie si la page actuelle appartient au type de publication personnalisé aktsii. Si c’est le cas, il cherche le fichier single-aktsii.php dans le dossier du thème enfant (get_stylesheet_directory()) et le retourne. Si le fichier n’est pas trouvé, il retourne le $template par défaut inchangé.
4.2. Exemple: plusieurs CPT avec un seul gestionnaire
Si vous avez plusieurs types de publication personnalisés, il est pratique de consolider la logique dans un seul filtre:
1 add_filter( 'template_include', 'techblog_cpt_templates', 99 ); 2 3 function techblog_cpt_templates( $template ) { 4 $cpt_templates = array( 5 'aktsii' => 'single-aktsii.php', 6 'portfolio' => 'single-portfolio.php', 7 'testimonials' => 'single-testimonials.php', 8 ); 9 10 foreach ( $cpt_templates as $cpt => $template_file ) { 11 if ( is_singular( $cpt ) ) { 12 $custom_template = get_stylesheet_directory() . '/' . $template_file; 13 if ( file_exists( $custom_template ) ) { 14 return $custom_template; 15 } 16 } 17 } 18 19 return $template; 20 }
Désormais, chaque CPT obtient son propre template, et toute la logique réside dans une seule fonction.
4.3. Stocker les templates dans une extension
Si vous distribuez le type de publication personnalisé en tant qu’extension (plutôt qu’en tant que partie d’un thème), il est logique de stocker le template dans le dossier de l’extension. Dans ce cas, spécifiez le chemin via plugin_dir_path( __FILE__ ):
1 add_filter( 'template_include', 'myplugin_cpt_template', 99 ); 2 3 function myplugin_cpt_template( $template ) { 4 if ( is_singular( 'aktsii' ) ) { 5 $custom_template = plugin_dir_path( __FILE__ ) . 'templates/single-aktsii.php'; 6 if ( file_exists( $custom_template ) ) { 7 return $custom_template; 8 } 9 } 10 return $template; 11 }
Ce modèle est utilisé par de nombreuses extensions populaires (WooCommerce, Easy Digital Downloads, The Events Calendar): elles embarquent les templates en interne et les incluent via le filtre.
5. Créer le type de publication personnalisé
Nous avons le template prêt, mais pour être complet, quelques mots sur l’origine du type de publication personnalisé lui-même.
5.1. Enregistrement via code
Un enregistrement CPT minimal dans functions.php ou un MU-plugin:
1 add_action( 'init', 'techblog_register_cpt_aktsii' ); 2 3 function techblog_register_cpt_aktsii() { 4 $labels = array( 5 'name' => 'Promotions', 6 'singular_name' => 'Promotion', 7 'menu_name' => 'Promotions', 8 ); 9 10 $args = array( 11 'labels' => $labels, 12 'public' => true, 13 'has_archive' => true, 14 'supports' => array( 'title', 'editor', 'thumbnail' ), 15 'rewrite' => array( 'slug' => 'aktsii' ), 16 'show_in_rest' => true, 17 ); 18 19 register_post_type( 'aktsii', $args ); 20 }
Le détail clé ici est que le paramètre 'rewrite' => array( 'slug' => 'aktsii' ) définit le slug utilisé à la fois dans l’URL et dans le nom du fichier de template. Si le slug est aktsii, le fichier de template doit être nommé single-aktsii.php.
5.2. Utiliser l’extension Custom Post Type UI
Si vous préférez ne pas modifier functions.php, vous pouvez créer un CPT visuellement en utilisant l’extension gratuite Custom Post Type UI sur WordPress.org. Après installation:
- Dans le panneau d’administration, allez dans CPT UI → Add/Edit Post Types
- Remplissez les champs: Post Type Slug (caractères latins), Plural Label, Singular Label
- Dans l’onglet Settings, sélectionnez les fonctionnalités d’éditeur dont vous avez besoin (titre, éditeur, image mise en avant)
- Cliquez sur Add Post Type
L’extension génère le code PHP d’enregistrement, que vous pouvez exporter et coller dans functions.php. C’est pratique si vous souhaitez plus tard supprimer la dépendance à l’extension. Le slug que vous avez spécifié dans CPT UI est celui qui entre dans le nom du fichier de template.
⁉️🤔 Questions fréquentes
Que dois-je faire si le template n’est pas pris en compte après la création du fichier?
Régénérez les permaliens: allez dans Réglages → Permaliens et cliquez sur «Enregistrer les modifications» (vous n’avez rien besoin de changer). WordPress reconstruira ses règles de routage. Si cela ne résout pas le problème, vérifiez le nom du fichier: le slug du type de publication personnalisé et le nom du fichier doivent correspondre (casse, tirets et underscores). En troisième étape, videz le cache de votre extension de cache, si elle est installée. Les permaliens doivent être régénérés après l’enregistrement de tout nouveau type de publication personnalisé, pas seulement lorsque vous rencontrez des problèmes de template. C’est une pratique standard: allez dans Réglages → Permaliens → Enregistrer, et les nouvelles URL fonctionnent immédiatement.
Puis-je utiliser un seul template pour plusieurs types de publication personnalisés?
Oui, de deux manières. Premièrement, créez un fichier physique
single-aktsii.php, et pour le second type (disonsportfolio), copiez-le en tant quesingle-portfolio.php. Deuxièmement, utilisez le filtretemplate_include(section 4): dans le tableau$cpt_templates, pointez différents types vers le même fichier de template. En pratique, cependant, des CPT différents ont presque toujours des mises en page différentes; copier et modifier est plus simple que de construire une logique conditionnelle à l’intérieur d’un seul template. Si vous avez vraiment de nombreux types avec une logique identique, créez unsingle-cpt.phppartagé, vérifiezget_post_type()à l’intérieur et incluez la partie de template correspondante viaget_template_part( 'template-parts/content', get_post_type() ). C’est une approche propre et évolutive.
Dois-je créer archive-{post_type}.php** pour la page d’archive?**
C’est recommandé mais pas obligatoire. Sans cela, WordPress utilise
archive.phpouindex.php. Si le CPT a'has_archive' => trueet que l’archive s’ouvre à/aktsii/mais qu’il n’y a pas de fichierarchive-aktsii.php, learchive.phpgénérique sera utilisé. Créer un template d’archive séparé a du sens lorsque la grille d’articles, la disposition en colonnes ou la barre latérale doivent différer de l’archive du blog.
Cela fonctionne-t-il avec les thèmes en blocs (FSE)?
Dans les thèmes en blocs, les fichiers de template PHP classiques ne sont pas l’approche principale. Cependant, le filtre
template_include(section 4) fonctionne aussi en FSE: vous pouvez placersingle-aktsii.phpdans un thème enfant ou une extension et l’inclure via le filtre. Alternativement, dans l’Éditeur de site, vous pouvez créer un template pour un type de publication personnalisé spécifique via l’interface: Apparence → Éditeur → Templates → Ajouter un nouveau template → Single Item: Aktsii. WordPress l’enregistrera en tant que template HTML dans la base de données, et il fonctionnera sans aucun fichier dans le thème.
Que choisir en 2026: fichier ou filtre?
Une matrice de décision rapide pour choisir l’approche:
Scénario | Quoi utiliser |
|---|---|
Thème classique, un ou deux CPT | Fichier |
Thème enfant, vous ajoutez le CPT | Fichier dans le thème enfant, survit aux mises à jour du thème parent |
Thème en blocs (FSE), CPT via une extension | Filtre |
CPT distribué en tant qu’extension | Filtre + template dans le dossier de l’extension |
Nombreux CPT avec une structure similaire | Filtre + |
En pratique, chez techblog.sdstudio.top, nous utilisons le plus souvent une combinaison: enregistrer le CPT via code dans un MU-plugin et placer les templates en tant que fichiers dans un thème enfant. Cela donne une prise en charge automatique sans filtres supplémentaires, et les mises à jour du thème parent ne cassent rien.
Si vous commencez tout juste à apprendre les types de publication personnalisés, commencez par le fichier single-{post_type}.php. Cela prend cinq minutes et donne des résultats immédiats. Lorsque vous sentirez que l’approche par fichier ne suffit plus (vous devez charger des templates depuis une extension ou les échanger à la volée), passez à template_include. Les deux méthodes sont parfaitement légitimes et prises en charge par le cœur de WordPress.



