Table des matières
Les thèmes Ghosts, c'est cool, on peut faire beaucoup de modifications avec le code injection. En revanche, si vous voulez vraiment paramétrer votre thème pour qu'il suive certaines règles automatiquement et donc que vous n'ayez pas à rajouter du code injection en script ou en CSS pour chaque cas de figure, il va falloir mettre les mains dans le cambouis et toucher aux fichiers du thème.
Je vais essayer de vous détailler les différents fichiers que j'ai modifiés et qui sont (selon moi) les plus importants dans un thème Ghost.
Il faut savoir qu'un thème Ghost est écrit en HBS, aussi appelé "Handlebars", un langage que je n'avais jamais rencontré auparavant.
Il est organisé comme suit :


📂 Rôle des principaux fichiers dans un thème Ghost
Élément / Fichier | Portée / Type | Exemple de fichier | Que contient-il ? |
---|---|---|---|
Template principal | Page d’accueil | index.hbs |
Point d’entrée principal du site, appelle les blocks comme grid-posts , classic-posts , intro texte, etc. |
Template de page | Pages CMS (ex. à propos, contact) | page.hbs |
Rendu d’une page unique écrite dans Ghost, avec {{content}} , titre, image principale. |
Template de tag (défaut) | Liste les articles qui ont un certain tag (x) | tag.hbs |
Rendu d’une page /tag/x/ , avec header personnalisé (le nom du tag et une description) et la liste d’articles en dessous. |
Template de tag (personnalisé) | Liste des articles d’un tag (x) avec un affichage particulier | tag-x.hbs . |
Rendu d’une page /tag/x/ avec un affichage personnalisé. Court-circuite grid-post |
Listing / Grille | Liste d’articles (home, tag...) | home-blocks/grid-posts.hbs |
Boucle sur plusieurs posts, appelle article-router.hbs , gère Masonry, nombre de colonnes. |
Router de post | Choix de la tuile à utiliser | loop/article-router.hbs |
En fonction des tags (arc , quete , etc.), choisit le bon layout d’article : grid-article , arc-article , quete-article . |
Tuile d’article standard | Carte cliquable d’un article | loop/grid-article.hbs |
Markup HTML d’un seul post (image, titre, extrait...), affiché dans les grilles. Aucun layout global, que la tuile. |
Tuile alternative | Pour arcs / quêtes / designs personnalisés | loop/arc-article.hbs , loop/quete-article.hbs |
Variante de grid-article , spécialement stylée pour les arcs ou quêtes. |
Template d’article complet | Vue détaillée d’un post | default-post-light.hbs (template de base) custom-template-perso.hbs (personnalisation) |
Un template de base permet de choisir ce qu'on veut dans tous nos articles. Un template un peu plus personnalisé permet de faire du cas par cas selon les articles. C'est ce template qu'on peut sélectionner lors de la création du post. |
Fichier de routing | Logique globale de routage Ghost | routes.yaml |
Définit quels fichiers hbs sont utilisés pour quelles URL (channels, collections...). Filtrage des posts possible par tag, auteur, etc. |
🧩 Et le fichier default.hbs
?
C’est le layout global du thème. Tous les fichiers .hbs
principaux (index.hbs
, tag.hbs
, etc.) héritent implicitement de lui grâce à la directive {{!< default}}
.
Il contient :
- le
<head>
avec les metas et le CSS, - les injections Ghost (
{{ghost_head}}
,{{ghost_foot}}
), - le
<body>
avec les classes utiles (home-template
,tag-template
, etc.), - un conteneur pour le contenu :
{{{body}}}
.
Il ne décide d’aucun contenu, mais il enveloppe tous les autres. C’est donc le bon endroit pour :
- les scripts JS globaux,
- les hooks CSS communs,
- le layout de base (header/footer/nav).
🧭 Comment ça s'imbrique ?
À chaque étape du processus, c’est le routes.yaml
qui est consulté en premier. routes.yaml
va donner des directives.
Ce fichier est présent en dehors du thème, il est accessible dans le setting de ghost dans le lab (ghost v5)
S’il est vide alors il y a 4 cas de figure principaux à connaître que Ghost va suivre pour choisir ce qu'il affiche sur la page.
1. Page d’accueil (index)
index.hbs
└─ home-blocks/grid-posts.hbs
└─ loop/article-router.hbs
├─ loop/grid-article.hbs (par défaut)
├─ loop/quete-article.hbs (si tag quete/now)
└─ loop/arc-article.hbs (si tag arc)
- L’URL est la racine (pas une page particulière). On est donc sur la page d’accueil. Cela déclenche la page
index.hbs
qui appelle le fichier qui gère l’agencement des posts entre eux (grid-posts
). grid-posts
dit alors (dans mon cas) « affiche les posts au format Masonry (2 colonnes, 6 articles maximum par page, pagination) » et appellearticle-router
.article-router
détermine l’affichage de la tuile en fonction de certaines caractéristiques (par exemple, la présence d’un tag).
2. Page particulière
Si on arrive sur une URL de type site.com/page
, alors c’est page.hbs
qui est utilisé. Pas besoin d’entrer dans les détails ici, Ghost gère très bien cette partie.
3. Page de tag particulier
Dans Ghost, chaque tag peut avoir sa propre page (/tag/nomdutag), listant tous les articles qui le contiennent. C’est extrêmement pratique pour organiser ses contenus.
Mais parfois, on veut un affichage particulier pour certains tags. Exemple :
- https://world.matthieucousin.com/tag/now/
- https://world.matthieucousin.com/tag/quete/
- https://world.matthieucousin.com/tag/arc/
Dans ce cas :
- Ghost va chercher un fichier
tag-<slug>.hbs
(ex.tag-quete.hbs
pour/tag/quete/
). - Si ce fichier existe, il est utilisé à la place de
tag.hbs
.
⚠️ C’est une solution simple mais peu robuste. Ghost choisittag-quete.hbs
uniquement par convention de nommage, pas parce qu’on lui a demandé explicitement. En cas de mise à jour du core de Ghost, cela pourrait sauter.
Il vaut mieux définir cela dansroutes.yaml
.
Si on utilise un fichier tag-quete.hbs
:
- Il fixe son propre agencement (sans passer par
grid-posts
si on ne lui demande pas). - Il appelle directement un type de tuile (ex :
quete-article.hbs
), sans passer pararticle-router
.
Illustration sur mon blog personnel :
/tag/arc/
→tag-arc.hbs
→arc-article.hbs
/tag/quete/
→tag-quete.hbs
→quete-article.hbs
/tag/now/
→tag-now.hbs
→quete-article.hbs
4. Page de tag sans règle particulière
Si aucun fichier spécial n’est trouvé pour l'url demandée, qu'on est pas sur la page d'acceuil et qu'on est ur une page de tag, Ghost utilise tag.hbs
.
tag.hbs
affiche le nom et la description du tag.- Il appelle
grid-posts.hbs
pour gérer l'agencement des tuiles de post entre elles grid-posts
appellearticle-router.hbs
pour gérer l'apparence de chaque tuilearticle-router
choisit le bon template de tuile selon les tags (ex :grid-article.hbs
,arc-article.hbs
, etc.).
Navigateur → URL → routes.yaml (si non vide) → index.hbs / tag.hbs
↓
grid-posts.hbs
↓
article-router.hbs
↙ ↓ ↘
grid-article quete-article arc-article
🛣️ Alternative : routes.yaml en pilote principal
Avec routes.yaml
, on peut tout définir plus proprement les fichiers que doit utiliser ghost selon l'url. Exemple de mon fichier route.yaml
routes:
/tag/arc/:
controller: channel
template: tag-arc
filter: 'tag:arc'
data: tag.arc # slug explicite → description OK
/tag/quete/:
controller: channel
template: tag-quete
filter: 'tag:quete'
data: tag.quete
/tag/now/:
controller: channel
template: tag-now
filter: 'tag:now+tag:quete'
data: tag.now
collections:
/: # Accueil
permalink: /{slug}/
template: index
filter: 'primary_tag:-[arc,quete]' # masque arc/quete seulement ici
order: 'published_at desc'
taxonomies: # ← laisse Ghost servir TOUS les autres /tag/{slug}/
tag: /tag/{slug}/
author: /author/{slug}/
URL | Template appelé | Source du mapping | {{tag}} dispo ? |
Remarques utiles |
---|---|---|---|---|
/ |
index.hbs |
collections dans routes.yaml |
✖ | Accueil ; liste tous les articles selon le filtre de collection |
/tag/arc/ |
tag-arc.hbs |
routes explicite |
✅ data.tag.arc |
Page spéciale pour les arcs (timeline, etc.) |
/tag/quete/ |
tag-quete.hbs |
routes explicite |
✅ data.tag.quete |
Page spéciale pour les quêtes |
/tag/now/ |
tag-now.hbs |
routes explicite |
✅ data.tag.now |
Page spéciale pour les quêtes en cours |
/tag/{slug}/ (ex. /tag/voyage/ ) |
tag.hbs |
taxonomies dans routes.yaml |
✅ automatiquement | Rendu dynamique pour les autres tags |
Je ne maîtrise malheureusement pas très bien ce fichier route.yaml. Je suis preneur si vous avez des suggestions.
La seule limite que je donnerais à route.yaml, c'est que comme on ne peut pas mettre de JavaScript et qu'on ne peut pas utiliser un langage très complexe, il est difficile de faire un filtrage fin de certains éléments, par exemple filtrer des primary tags de manière fine (sur un nom excate et pas seulement un "include")
Le route.yaml est excellent pour mettre en place des règles d'affichage simples sur son site. Dès que les règles sont complexe, il vaut mieux passer par des appels de fichier hbs directement das le thème
🛠️ Points clés pour la personnalisation
Action | À modifier |
---|---|
Masquer les articles avec les tags arc ou quete |
Dans grid-posts.hbs (filtrage Handlebars ou JS). En pratique, je n'ai pas réussi. |
Styliser différement les tuiles par défaut | Agir sur grid-article.hbs
|
Modifier la structure d’une page de tag | Dans tag.hbs ou tag-*.hbs . |
Changer l’agencement des tuiles sur une page | Dans grid-posts.hbs . |
Ajouter un nouveau type de tuile | Créer loop/mon-type-article.hbs , puis l’intégrer à article-router.hbs . |
Ajouter un badge ou ruban à une tuile | Ajouter des classe css dans grid-article.hbs , avec des conditions d’affichage. |
Styliser avec des hooks CSS | Utiliser les classes ajoutées dans les .hbs (.grid-33 , .quete-card , etc.). |
❌ Les limites que j’ai rencontrées
J’ai réussi à personnaliser mon thème comme je le voulais sur certaines pages de tags spécifiques, en particulier :
J’ai aussi pu créer des pages de tags comme :
Mais j’aurais aimé empêcher l’affichage de certains types d’articles ailleurs que sur leur page dédiée. Notamment les articles avec un primary_tag
comme "quête" ou "arc", qui ont un affichage non compatible avec Masonry. Ils déforment visuellement la page d’accueil ou les autres tags.
Après de nombreux essais infructueux, voici ce que j’ai observé :
- Les filtres sur
primary_tag
sont difficiles à implémenter avec du handle bar, surtout si il faut faire la différence entre un tag exacte (exemple : arc) et un tag qui contient arc (exemple arc-1) - La pagination se casse lorsqu’on essaie de filtrer avec
{{#get}}
. - Le Masonry devient instable avec certains layouts.
Sur ce point, je suis preneur de solutions ou de conseils.
🚧 Pistes d'amélioration
- Centraliser la logique dans
routes.yaml
pour éviter lestag-x.hbs
redondants. - Ne pas court-circuiter
grid-post.hbs
avectag-x.hbs
: créer un équivalent propre pour les pages (ex. ungrid-router.hbs
). - Ajouter des règles JS pour mieux gérer les exclusions dynamiques.
🧩 Conclusion
Modifier un thème Ghost en profondeur peut sembler intimidant au départ, surtout quand on découvre Handlebars pour la première fois. Mais une fois la logique comprise — entre les fichiers de structure, les templates de tuiles, le routes.yaml,
on se rend compte qu’on peut vraiment créer une expérience sur mesure. N'hésitez pas à demander de l'aide à ChatGPT mais attention il peut vous faire tourner en boucle un moment !
Ce guide n’a pas vocation à être exhaustif, mais à partager ce que j’ai appris en pratiquant, avec mes réussites et mes limites. Si ça peut éviter à d'autres de perdre des heures à débuguer une page d’accueil cassée ou un tag qui n’affiche pas ce qu’il faut, c’est déjà une victoire.
Et si vous avez trouvé d’autres astuces, des contournements élégants ou des bonnes pratiques à partager, je suis preneur !