#Tags
Un tag pilote le rendu : condition, boucle, affectation, inclusion. Webcosa
n’ajoute qu’un seul tag à ceux de Liquid — section — et en retire zéro. Cette
page dit lesquels sont réellement enregistrés, ce que fait celui qui est propre à
Webcosa, et les trois pièges qui coûtent une demi-heure quand on ne les connaît
pas.
Contrairement aux variables et aux filtres, un tag inconnu n’est pas ignoré : il fait échouer l’analyse du fichier, et toute la section est remplacée par un commentaire HTML. C’est la différence la plus importante à retenir de cette page.
#Ce qui est enregistré
| Tag | Origine | Ce qu’il fait |
|---|---|---|
if / elsif / else / unless | Liquid | condition |
case / when | Liquid | aiguillage sur une valeur |
for / break / continue | Liquid | boucle |
tablerow | Liquid | boucle qui produit un tableau HTML |
cycle | Liquid | alterne des valeurs d’un tour à l’autre |
assign | Liquid | affecte une variable |
capture | Liquid | affecte le HTML produit par un bloc |
increment / decrement | Liquid | compteur de page |
echo | Liquid | écrit une expression, utile dans liquid |
liquid | Liquid | plusieurs tags sans répéter les délimiteurs |
render | Liquid | insère un snippet, en portée isolée |
include | Liquid | insère un snippet, en portée partagée |
comment | Liquid | commentaire non rendu, sur plusieurs lignes |
# | Liquid | commentaire d’une ligne : {% # … %} — le seul qui marche dans un bloc {% liquid %} |
raw | Liquid | rend le Liquid sans l’exécuter |
block / layout | Liquid | héritage de gabarit — inutilisable ici |
section | Webcosa | pose une section depuis la coquille |
Et schema, qui n’est pas un tag du tout : voir plus bas.
#Les tags de tous les jours
Les quatre thèmes livrés — Origo, Forge, Vela, Piazza — n’en utilisent que six :
if, for, comment, render, assign et section. Ce n’est pas de la
frugalité de façade : un thème de site vitrine n’a rien à calculer, il a des
choses à afficher ou à ne pas afficher.
#if, elsif, else
La forme la plus fréquente dans un thème est le test « ce réglage est-il
rempli ? ». Elle s’écrit avec blank, qui vaut pour une chaîne vide comme pour
une valeur absente.
{%- if section.settings.surtitre != blank -%}
<span class="surtitre">{{ section.settings.surtitre }}</span>
{%- endif -%}Ce test partout autour du balisage est ce qui distingue un thème qu’on peut
livrer d’un thème de démonstration. Sans lui, un client qui vide le champ
« Surtitre » obtient un span vide qui garde sa marge : un trou dans la page,
sans explication et sans moyen de le refermer.
Les opérateurs sont ceux de Liquid : ==, !=, >, <, >=, <=, and,
or, contains. Il n’y a pas de parenthèses : and lie plus fort que or,
et une condition qui demande des parenthèses demande en réalité une variable
intermédiaire posée par assign.
#for
{%- for article in articles limit: section.settings.nombre -%}
<h3><a href="{{ article.adresse }}">{{ article.titre }}</a></h3>
{%- endfor -%}Les paramètres limit:, offset: et reversed fonctionnent, et limit: accepte
une variable — ici la valeur d’un réglage range, ce qui rend le nombre de
cartes réglable depuis l’éditeur sans toucher au code.
Dans la boucle, l’objet forloop donne index (à partir de 1), index0,
first, last, length et rindex.
{%- for bloc in section.blocks -%}
<li><span class="etape-rang">{{ forloop.index }}</span> …</li>
{%- endfor -%}{% for i in (1..99999999) %} ne bloque pas le serveur, mais il ne rend rien
d’utile non plus : au bout de trois secondes, LiquidJS interrompt le rendu et la
section entière devient
<!-- section boucle : template render limit exceeded, line:1, col:1 -->.
Les bornes sont détaillées sur la page du bac à sable.
#assign et capture
assign pose une variable, capture pose le HTML produit par un bloc.
{% assign fond = section.settings.fond | default: 'papier' %}
<section class="section section-{{ fond }}">
{% capture classes %}carte carte-{{ bloc.type }}{% endcapture %}
<article class="{{ classes }}">Une variable posée par assign vit jusqu’à la fin du rendu du fichier courant.
Elle ne traverse pas un render — voir juste en dessous.
#comment
{%- comment -%}
Le bouton du thème, en un seul endroit.
{%- render 'bouton', label: 'Nous écrire', href: '/contact' -%}
Rien ne s'affiche si le libellé est vide : c'est ce qui permet de poser
deux boutons dans une section et de n'en garder qu'un depuis l'éditeur,
sans laisser un rectangle vide à la place du second.
{%- endcomment -%}Un snippet réutilisable sans en-tête est un snippet que personne n’ose appeler. Les trois snippets d’Origo commencent tous par un commentaire qui montre l’appel et dit ce que le snippet refuse de rendre — c’est la convention du dépôt, et elle vaut la peine d’être reprise.
#render et include : la vraie différence
Les deux insèrent un fichier de snippets/. Ils ne se comportent pas du tout
pareil, et c’est de loin la surprise la plus fréquente.
Le snippet ne voit que les paramètres qu’on lui passe. Ni site, ni page,
ni settings, ni section, ni les variables posées par assign dans la section
appelante.
{%- render 'bouton', label: section.settings.cta_label, href: section.settings.cta_href -%}Le snippet voit tout le contexte de l’appelant, et peut même y écrire. C’est la forme historique de Liquid, et Shopify la déconseille depuis longtemps.
{%- include 'bouton' -%}Dans un snippet appelé par render, {{ site.nom }} rend du vide. C’est
correct, c’est voulu, et ça surprend tout le monde une fois. Si ton snippet a
besoin du nom du site, passe-le :
{%- render 'pied-mention', nom: site.nom -%}.
C’est ce qui rend un snippet lisible : ses entrées sont écrites à l’appel, et on n’a pas à lire son corps pour savoir de quoi il dépend.
Préfère render partout. include fonctionne, mais un snippet qui lit le
contexte de son appelant crée un couplage invisible : déplacer l’appel d’une
section à une autre le casse sans qu’aucune ligne du snippet n’ait changé.
{%- if label != blank -%}
<a class="bouton{% if style == 'secondaire' %} bouton-secondaire{% endif %}"
href="{{ href | default: '/contact' }}">{{ label }}</a>
{%- endif -%}Le nom du snippet se donne sans dossier ni extension : 'bouton' désigne
snippets/bouton.liquid. Le moteur complète les deux. Un snippet introuvable
fait échouer le rendu de la section, qui devient un commentaire.
#section — le tag propre à Webcosa
{% section 'entete' %} pose une section depuis la coquille. C’est lui qui rend
l’en-tête et le pied modifiables comme le reste : sans lui, il faudrait les
écrire en dur dans layout/theme.liquid, donc les sortir de l’éditeur et du
schéma.
{% section 'annonce' %}
{% section 'entete' %}
<main id="contenu">{{ content_for_layout }}</main>
{% section 'pied' %}Ce qu’il fait exactement, dans l’ordre :
Il cherche le fichier
sections/<nom>.liquid. S’il n’existe pas, il rend<!-- section absente : <nom> -->et le reste de la page continue. Une coquille qui appelle une section qu’un thème n’a pas ne casse donc rien.Il lit ses réglages dans settings_data.json
Sous
current.sections.<nom>. Ces valeurs sont fusionnées par-dessus les"default"du{% schema %}de la section : ce qui n’a pas été renseigné prend le défaut.json{ "current": { "sections": { "entete": { "settings": { "cta_label": "Nous contacter", "cta_href": "/contact" } } } } }Il rend la section avec le contexte de la page
site,page,settings,menu,articles— tout est là, plus l’objetsectionde l’instance. Contrairement àrender,sectionne coupe pas la portée du contexte global.
L’imbrication est plafonnée à six niveaux, et le compteur vit hors de portée
du thème. Au-delà, le tag rend
<!-- sections trop imbriquées à « <nom> » -->. C’est ce qui arrête une section
qui s’appelle elle-même — par accident, ou pour voir.
Une section posée par la coquille déclare "group": "header" ou "footer" dans
son schéma. Le détail est sur la page des schémas, et la
composition d’une page ordinaire sur celle des templates.
#schema n’est pas un tag
{% schema %} ressemble à un tag, s’écrit comme un tag, et n’en est pas un.
Aucun tag de ce nom n’est enregistré dans le moteur : le bloc est découpé du
fichier par une expression régulière avant que Liquid ne voie quoi que ce soit.
Son contenu est du JSON pur, lu à part.
Le découpage ne retire que la première paire schema / endschema du
fichier. Un second bloc schema survit donc jusqu’à l’analyse, où il n’existe
pas — et toute la section devient :
<!-- section deux : tag "schema" not found, line:1, col:3 -->Un seul bloc schema par fichier de section, à la fin. C’est aussi la convention
Shopify, et le moteur n’en accepte pas d’autre.
Corollaire utile : {% schema %} n’a de sens que dans sections/. Dans la
coquille ou dans un snippet, il serait retiré silencieusement du rendu et ignoré
de tout le reste.
#Les tags qui existent mais ne servent pas
layout est enregistré par LiquidJS, mais inutilisable ici. Le système de
fichiers du moteur résout les noms nus vers snippets/, et surtout : la coquille
n’est pas appliquée par un tag, elle est appliquée par le rendu, qui rend les
sections puis les injecte dans layout/theme.liquid par content_for_layout.
{% layout 'theme' %} produit
ENOENT: Failed to lookup "theme" in "." et fait échouer la section.
block n’a de sens qu’avec layout. Même conclusion.
increment, decrement, cycle, tablerow fonctionnent parfaitement, et
aucun thème livré ne les emploie. Ils sont mentionnés pour que personne ne perde
de temps à chercher un équivalent : cycle alterne des classes d’une ligne sur
deux, tablerow produit un vrai tableau HTML, increment porte un compteur
partagé par toute la page.
#Les tags qui n’existent pas
Ceux-là viennent de Shopify et font échouer l’analyse. Le message est le même pour tous, au nom près.
| Écrit dans une section | Résultat |
|---|---|
{% form 'contact' %} | <!-- section … : tag "form" not found --> |
{% paginate a by 2 %} | <!-- section … : tag "paginate" not found --> |
{% style %} | <!-- section … : tag "style" not found --> |
{% javascript %} | même chose |
{% stylesheet %} | même chose |
Ce n’est pas comme un filtre inconnu, qui laisse passer la valeur. Un tag inconnu
emporte la section entière : la page rend, mais ce bloc-là a disparu, remplacé
par un commentaire HTML. Si un bandeau manque après avoir copié du code Shopify,
ouvre le code source de la page et cherche <!-- section.
Ce qu’il faut écrire à la place : une balise form HTML ordinaire qui poste vers
/api/contacts (c’est ce que fait la section Contact des quatre thèmes), une
balise style HTML dans la coquille pour les variables CSS, et le fichier
assets/theme.css pour tout le reste. La liste complète des absences et de leurs
remplacements est sur la page des absents.
#Le contrôle des espaces
{%- et -%} mangent les espaces et les sauts de ligne autour du tag. Les
thèmes livrés les emploient systématiquement à l’intérieur des sections, et pas
sur les tags de premier niveau de la coquille — pour que le HTML rendu reste
lisible quand on l’inspecte.
{% if x %}
<p>a</p>
{% endif %}
→ un saut de ligne et deux espaces autour de <p>a</p>
{%- if x -%}
<p>a</p>
{%- endif -%}
→ <p>a</p>Ce n’est pas cosmétique partout : dans un contexte où l’espace compte — entre
deux éléments inline-block, dans un attribut construit par morceaux — un saut
de ligne laissé par un if se voit à l’écran.

