Templates
Écrire un template de post, les propriétés qu'il reçoit, la portée par type et la chaîne de repli.
Le module fournit un template minimal pour que l'installation soit vérifiable, puis s'efface. La mise en page appartient au projet, ce qui permet de garder son branding sans forker le module.
Le registre de templates vit dans le core, dans core/templates, et il est partagé par tous les modules de contenu. Les templates de posts sont ceux de kind: 'post'.
Un template est lié à un type
C'est la différence structurante avec les templates de page : un template de post porte en plus un postType. La clé de résolution est le triplet (kind, postType, id).
Un template déclaré pour blogue n'apparaît donc jamais dans le sélecteur d'un post de type expertise, et deux types peuvent avoir chacun leur propre template default sans se marcher dessus.
Écrire un template
Déposer un fichier dans components/lrvo/templates/ du projet hôte :
// components/lrvo/templates/article.js
export const meta = {
id: 'article',
label: 'Article',
kind: 'post',
postType: 'blogue',
};
export default function ArticleTemplate({ post, blocks, url, breadcrumb }) {
return (
<main>
<h1>{post.title}</h1>
<Content blocks={blocks} />
</main>
);
}npx lrvo-modules sync scanne ce dossier et génère le manifeste app/.lrvo/templates.server.js, qui enregistre les templates au boot. Le formulaire d'édition liste alors les templates du type courant dans son sélecteur.
Omettre postType sur un template de kind: 'post' fait échouer l'enregistrement au boot, avec une erreur explicite. C'est voulu : mieux vaut tomber au démarrage qu'au premier rendu.
Propriétés reçues
| Propriété | Type | Contenu |
|---|---|---|
post | objet | Le post complet, données aplaties au premier niveau, plus _data, parent_id, sort_order, visibility, created_at, updated_at, et les taxonomies et relations résolues. |
blocks | tableau | Concaténation de tous les champs de type editor du type, dans l'ordre de déclaration. |
url | chaîne | Chemin canonique du post. |
breadcrumb | tableau | { id, slug, title, url } de la racine au post courant inclus. |
Aucun children n'est injecté, le template décide seul de sa structure.
Deux clés non déclarables sur post
data porte deux clés qui ne viennent d'aucune déclaration de champ, et qui sont donc aplaties comme les autres : post.template, l'identifiant du template retenu, et post.seo, l'objet de métadonnées. Voir Modèle de données.
Un type hiérarchique ajoute par ailleurs post._path, le chemin public reconstruit depuis la chaîne des parents. Sa valeur est celle de la propriété url : préférer url, qui est présente quel que soit le type. _path existe surtout pour l'admin, qui s'en sert pour le lien « voir » d'une ligne de liste.
blocks quand il y a plusieurs champs editor
Un type peut déclarer plus d'un champ editor. La propriété blocks les aplatit en une seule liste, dans l'ordre où les champs sont déclarés.
Pour les rendre séparément, lire les champs directement plutôt que blocks :
export default function ArticleTemplate({ post }) {
return (
<main>
<Content blocks={post.intro} />
<aside><Content blocks={post.encadre} /></aside>
</main>
);
}Rendre les blocs
Deux options :
- Le composant
Contentdu projet, danscomponents/lrvo/templates/content.js, qui applique la typographie du site. BlockListRendererdu core, en repli neutre.
import BlockListRenderer from '@lrvo/core/blocks-registry/render';
<BlockListRenderer blocks={blocks} />Voir Blocs personnalisés pour ajouter ses propres types de blocs.
Fil d'Ariane
breadcrumb a exactement la même forme côté pages et côté posts. Un même composant sert donc aux deux. Pour un type sans champ parent, il contient un seul élément : le post lui-même.
export default function ArticleTemplate({ post, breadcrumb }) {
return (
<main>
<nav>
{breadcrumb.map((crumb) => (
<a key={crumb.id} href={crumb.url}>{crumb.title}</a>
))}
</nav>
<h1>{post.title}</h1>
</main>
);
}Aucune entrée d'accueil n'est ajoutée, et le premier élément n'est pas le type mais le post racine de la chaîne.
Remplacer le template par défaut
Le module enregistre lui-même, pour chaque type déclaré, un template default qui rend le titre puis les blocs bruts. Il n'a pas de mise en page.
Pour le remplacer, déclarer un template du projet avec le même identifiant :
export const meta = { id: 'default', label: 'Par défaut', kind: 'post', postType: 'blogue' };Les templates du projet sont enregistrés après ceux des modules, à clé égale ils gagnent. C'est ce qui permet de reprendre default sans toucher au module ni changer la valeur stockée sur chaque post.
Résolution
Au rendu, le module cherche le template dont l'identifiant vaut post.template, pour le type du post. À défaut, il retombe sur l'identifiant default du même type. À défaut encore, il rend le template minimal embarqué.
Un template supprimé du projet ne casse donc jamais les posts qui l'utilisaient : ils retombent sur default jusqu'à ce que leur champ soit changé.
Notes
- Le registre vit sur
globalThisviaSymbol.for. Il est partagé entre serveur et client et survit au rechargement à chaud. - Le module n'expose pas d'API impérative d'enregistrement de template : son registre interne n'est pas dans la carte d'exports du package. La voie déclarative par fichier est la seule voie publique, et reste préférable puisqu'elle est visible au
sync. meta.labelest ce que voit l'éditeur dans le sélecteur. Le garder lisible et distinct.