Aller au contenu

#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é

TagOrigineCe qu’il fait
if / elsif / else / unlessLiquidcondition
case / whenLiquidaiguillage sur une valeur
for / break / continueLiquidboucle
tablerowLiquidboucle qui produit un tableau HTML
cycleLiquidalterne des valeurs d’un tour à l’autre
assignLiquidaffecte une variable
captureLiquidaffecte le HTML produit par un bloc
increment / decrementLiquidcompteur de page
echoLiquidécrit une expression, utile dans liquid
liquidLiquidplusieurs tags sans répéter les délimiteurs
renderLiquidinsère un snippet, en portée isolée
includeLiquidinsère un snippet, en portée partagée
commentLiquidcommentaire non rendu, sur plusieurs lignes
#Liquidcommentaire d’une ligne : {% # … %} — le seul qui marche dans un bloc {% liquid %}
rawLiquidrend le Liquid sans l’exécuter
block / layoutLiquidhéritage de gabarit — inutilisable ici
sectionWebcosapose 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.

sections/journal.liquid — Origoliquid
{%- if section.settings.surtitre != blank -%}
  <span class="surtitre">{{ section.settings.surtitre }}</span>
{%- endif -%}
Astuce

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

sections/journal.liquid — Origoliquid
{%- 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.

sections/etapes.liquid — Forgeliquid
{%- for bloc in section.blocks -%}
  <li><span class="etape-rang">{{ forloop.index }}</span> …</li>
{%- endfor -%}
Danger

{% 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.

Les deux formesliquid
{% 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

snippets/bouton.liquid — Origoliquid
{%- 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.

liquid
{%- render 'bouton', label: section.settings.cta_label, href: section.settings.cta_href -%}
Danger

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é.

snippets/bouton.liquid — Origoliquid
{%- 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.

layout/theme.liquid — Origoliquid
{% section 'annonce' %}
{% section 'entete' %}

<main id="contenu">{{ content_for_layout }}</main>

{% section 'pied' %}

Ce qu’il fait exactement, dans l’ordre :

  1. 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.

  2. 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" } }
        }
      }
    }
  3. Il rend la section avec le contexte de la page

    site, page, settings, menu, articles — tout est là, plus l’objet section de l’instance. Contrairement à render, section ne coupe pas la portée du contexte global.

Attention

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.

Danger

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 :

html
<!-- section deux : tag &quot;schema&quot; 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 sectionRé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
Attention

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.

Avec et sansliquid
{% 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.