Fait avec Chinaski

Référence des templates

Un thème Chinaski est un répertoire plat de templates Template Toolkit 2 (.tt). Le processus de build rend vos templates en HTML statique pour chaque page et post, une fois par langue configurée. Cette page couvre les fichiers de thème, les variables qu'ils reçoivent, et les helpers et règles qui les accompagnent.

Où vivent les thèmes

  • Le thème par défaut intégré est livré avec l'application et sert de fallback.
  • Les thèmes personnalisés vivent dans builder/themes/<your-theme-slug>/. Quand un thème avec le slug du thème actif existe là, le builder l'utilise ; sinon il retombe sur les templates intégrés.
  • Le thème actif se choisit dans Settings.

Fichiers de template requis et optionnels

Fichier Rôle Requis ?
page.tt Template par défaut de chaque page publiée Oui
post.tt Template de chaque post de blog publié Oui
blog_index.tt Liste de blog paginée et pages de catégories Oui
404.tt Page 404 par langue Oui
_head.tt Partial <head> : CSS, balises meta, imports de polices Convention
_header.tt En-tête du site : logo, nav, tagline Convention
_footer.tt Pied de page du site : copyright, nav secondaire Convention
_cookie_notice.tt Bannière GDPR optionnelle Non
_sidebar.tt Partial de sidebar optionnel Non
search.tt Page de résultats de recherche optionnelle Non
_password_gate.tt UI de porte à mot de passe côté client pour les pages protégées Requis si page.tt/post.tt supporte password_hash
<custom>.tt N'importe quelle page qui le sélectionne via le réglage template Non

Les fichiers commençant par _ sont des partials et ne sont jamais rendus comme pages autonomes.

Variables de template

Les templates reçoivent un ensemble plat de variables ; il n'y a pas d'objets page. ou site.. Utilisez site_name, title, lang, etc. directement.

page.tt et 404.tt

Variable Type Notes
title string Titre de la page
body chaîne HTML Pré-rendu : ne l'échappez pas avec | html
slug string Slug d'URL
lang / language string Code à 2 lettres, ex. en
meta_title string? Outrepasse <title>
meta_description string? Description SEO
og_title string? Titre OpenGraph
og_description string? Description OG
og_image_url string? Image OG
canonical_url string Généré automatiquement
featured_image_url string? Image héro
featured_image_alt string? Texte alt
updated_at string Datetime SQLite
site_name string Depuis les réglages
site_tagline string Depuis les réglages
footer_copyright string Depuis les réglages
year integer Année de build
url_base string Préfixe d'URL : peut être vide ; préfixez TOUS les liens internes
cookie_notice_active 0/1 Rendre ou non _cookie_notice.tt
noindex 0/1 Émettre <meta name="robots" content="noindex">
nav_items array {label, url, slot, sort_order} : slot vaut header ou footer
hreflang_links array {hreflang, href} pour les traductions
breadcrumbs array {name, url, is_current}
json_ld chaîne HTML JSON-LD pré-sérialisé : émettez brut
ga4_id string? ID Google Analytics
gtm_id string? ID de conteneur GTM
twitter_site string? Handle Twitter avec @
password_hash string? Si défini, vous DEVEZ envelopper le contenu dans _password_gate.tt (voir ci-dessous)

post.tt : tout ce qui vient de page.tt, plus

Variable Type Notes
excerpt string Extrait fourni par l'auteur ; peut être vide
category string? Nom de la catégorie unique
tags string Séparés par des virgules ; découpez avec tags.split(',')
author string Nom affiché
is_sticky 0/1 Épinglé en tête de l'index du blog
published_at string? Datetime SQLite ; moment de la première publication
date string Tranche YYYY-MM-DD de published_at
feed_url string URL absolue du feed RSS
og_type string Toujours 'article'

blog_index.tt

Variable Type Notes
posts array Hash de posts triés avec les clés p.title, p.slug, p.date, p.body, p.category
pagination hash? {current_page, total_pages, prev_url, next_url, abs_prev_url, abs_next_url} : undef quand une seule page
title string « Blog » localisé ou nom de la catégorie
category_name string? Défini lors du filtrage par catégorie

search.tt

Variable Type Notes
query string Terme de recherche
results array {title, url, excerpt}
result_count integer Nombre total de correspondances

Blocks

Les auteurs placent des blocks en écrivant {{block:my-cta​}} dans un body de page ou de post. Au moment du build, le builder trouve le shortcode, recherche le block publié avec ce nom et cette langue, le rend avec son template, et substitue le HTML rendu dans le body.

Les templates de blocks sont partagés entre les thèmes et vivent hors de votre répertoire de thème ; votre thème est responsable du CSS qui style leur sortie.

Classes CSS que votre thème doit styler

Chaque type de block émet une classe wrapper prévisible et des classes internes. Votre _head.tt doit styler celles-ci :

Type Wrapper Classes internes
cta .cta-block .cta-inner .cta-heading .cta-subheading .cta-button
image .image-block .image-caption
quote .quote-block .quote-text .quote-attribution
hero .hero-block .hero-media .hero-inner .hero-heading .hero-subheading .hero-button
testimonial .testimonial-block .testimonial-label .testimonial-body .testimonial-avatar .testimonial-text .testimonial-attribution
stat .stat-block .stat-number .stat-label
promo .promo-block .promo-media .promo-content .promo-heading .promo-body .promo-button
embed .embed-block .embed-caption .embed-content
video .video-block .video-heading .video-wrapper .video-caption
form .form-block .form-heading .form-subheading .block-form .block-form__field
newsletter .newsletter-block .newsletter-inner .newsletter-heading .newsletter-subheading .newsletter-form .newsletter-form__row
accordion .accordion-block .accordion-heading .accordion .accordion__item .accordion__summary .accordion__body
table .table-block .table-heading .table-wrapper .block-table
columns .columns-block .columns-heading .columns .columns--2 .columns--3 .columns--4 .column .column__image .column__heading .column__body
gallery .gallery-block .gallery-heading .gallery .gallery__item

Style minimum requis pour les classes utilitaires :

  • .video-wrapper : position: relative; padding-bottom: 56.25%; avec l'iframe position: absolute; inset: 0; width: 100%; height: 100%; (vidéo responsive 16:9)
  • .columns--2 / .columns--3 / .columns--4 : display: grid avec les grid-template-columns appropriées
  • .table-wrapper : overflow-x: auto pour que les tables défilent sur mobile
  • .gallery : grille responsive avec gap
  • .accordion__item / .accordion__summary : reset basique details/summary

Pages multi-langues

  • Chaque page est rendue une fois par langue configurée.
  • Les liens internes doivent inclure le préfixe de langue : utilisez [% url_base %​]/[% lang %​]/contact/ ou similaire. La seule exception est nav_items[​].url, qui contient déjà l'URL complète correcte ; utilisez-la telle quelle.
  • L'élément <html> doit porter la langue : <html lang="[% lang | html %​]">.

Règles de sécurité

Les directives suivantes sont interdites dans le contenu des thèmes et des blocks et sont rejetées :

  • [% PERL %​] / [% RAWPERL %​]
  • [% INSERT '/absolute/path' %​]
  • [% USE ... %​] de modules comme File/IO/Socket/Net/LWP/WWW/HTTP/System/Cmd/Process/Pipe/Expect

Pages protégées par mot de passe

La protection par mot de passe est une porte tournée vers le lecteur : le contenu de la page est toujours présent dans le HTML publié, et _password_gate.tt le cache derrière une vérification JavaScript jusqu'à ce que le visiteur entre le bon mot de passe. page.tt et post.tt doivent l'implémenter comme ceci :

[% IF password_hash %​]
[% WRAPPER '_password_gate.tt' %​][% PROCESS page_content %​][% END %​]
[% ELSE %​]
[% PROCESS page_content %​]
[% END %​]

(Enveloppez quel que soit le bloc détenant votre contenu principal ; le nom exact du bloc n'importe pas, seulement qu'il soit défini et traité à l'intérieur du wrapper.) Si votre template omet entièrement la branche password_hash, un administrateur peut tout de même définir un mot de passe sur une page utilisant votre thème, et la page se rendra publiquement sans aucun avertissement que la porte est absente.

Anti-sèche

  • [% variable %​] : sortie brute
  • [% variable | html %​] : échappé en HTML (à utiliser pour TOUT texte contrôlé par l'utilisateur)
  • [% variable | uri %​] : encodage URI (pour les segments de chemin d'URL)
  • [% IF / ELSE / END %​], [% UNLESS ... %​] : conditionnelles
  • [% FOREACH item IN items %​] : boucles ; loop.index / loop.count disponibles
  • [% INCLUDE '_partial.tt' %​] : inclure un partial, en partageant les variables courantes ; ajoutez x = 42 pour passer ou masquer des valeurs
  • [% PROCESS '_macros.tt' %​] : comme INCLUDE mais sans introduire de nouvelle portée
  • [%- ... -%​] : rogne les blancs environnants

Pièges clés

  1. Stash plat : pas d'objets imbriqués. site.title, page.title, post.title sont tous faux ; utilisez site_name et title.
  2. Les champs des nav items sont label, url, slot : pas name, href, active.
  3. Les dates : n'appelez jamais le formatage de date sur published_at ; utilisez la variable date pré-calculée, ou prenez les 10 premiers caractères de published_at.
  4. Le body est du HTML pré-rendu : sortez [% body %​] sans échappement.
  5. Les partials sont préfixés par _.
  6. Tous les liens internes ont besoin de url_base et lang.
Lisez ce site en