Aller au contenu

#Écrire une section

Une section est un fichier de sections/ : du balisage, et à la fin un {% schema %} qui déclare ce qui est modifiable. C’est l’unité dont on compose une page — un bandeau d’accueil, une grille de prestations, un formulaire de contact — et c’est là que se passe l’essentiel du travail d’un thème.

Cette page montre comment on en écrit une, ce qu’elle reçoit au rendu, et les deux manières dont elle peut être appelée.

#Un exemple complet

Celui-ci est réel : c’est themes/origo/sections/prestations.liquid, réduit de moitié pour tenir sur un écran, mais rien n’y a été inventé.

sections/prestations.liquidliquid
<section class="section section-{{ section.settings.fond | default: 'papier' }} prestations" id="prestations">
  <div class="enveloppe">
    <div class="tete">
      {%- if section.settings.surtitre != blank -%}
        <span class="surtitre">{{ section.settings.surtitre }}</span>
      {%- endif -%}
      {%- if section.settings.titre != blank -%}
        <h2 class="titre titre-section">{{ section.settings.titre }}</h2>
      {%- endif -%}
    </div>

    <div class="grille grille-{{ section.settings.colonnes | default: '3' }}">
      {%- for bloc in section.blocks -%}
        <article class="carte">
          <h3>{{ bloc.settings.nom }}</h3>
          {%- if bloc.settings.description != blank -%}
            <p>{{ bloc.settings.description }}</p>
          {%- endif -%}
          {%- if bloc.settings.prix != blank -%}
            <span class="prix">{{ bloc.settings.prix }}</span>
          {%- endif -%}
        </article>
      {%- endfor -%}
    </div>
  </div>
</section>

{% schema %}
{
  "name": "Prestations",
  "settings": [
    { "type": "text", "id": "surtitre", "label": "Surtitre", "default": "Ce qu'on fait" },
    { "type": "text", "id": "titre", "label": "Titre", "default": "Nos prestations" },
    {
      "type": "select",
      "id": "colonnes",
      "label": "Colonnes",
      "options": [
        { "value": "2", "label": "Deux" },
        { "value": "3", "label": "Trois" },
        { "value": "4", "label": "Quatre" }
      ],
      "default": "3"
    }
  ],
  "blocks": [
    {
      "type": "prestation",
      "name": "Prestation",
      "settings": [
        { "type": "text", "id": "nom", "label": "Nom", "default": "Une prestation" },
        { "type": "textarea", "id": "description", "label": "Description" },
        { "type": "text", "id": "prix", "label": "Prix", "default": "sur devis" }
      ]
    }
  ],
  "max_blocks": 12
}
{% endschema %}

#L’anatomie du fichier

  1. Le nom du fichier est l’identifiant de la section

    sections/prestations.liquid répond au "type": "prestations" d’un template, et à {% section 'prestations' %} dans la coquille. Il n’y a pas d’autre déclaration à faire : le fichier suffit.

  2. Le balisage, en premier

    Du HTML, avec des expressions Liquid dedans. Tout ce qui précède le {% schema %} est rendu ; le bloc schema lui-même est retiré avant le rendu.

  3. Le schéma, à la fin

    Du JSON pur, entre {% schema %} et {% endschema %}. Par convention il est posé en dernier, et c’est ainsi que Shopify le lit aussi. Voir Le bloc schema.

#Ce que la section reçoit

Au rendu, une section voit le contexte complet du sitesite, page, settings, menu, articles, annee — plus un objet section qui n’existe que pour elle.

section.idchaîne

L’identifiant de l'instance. Pour une section de template, c’est la clé sous laquelle elle est déclarée ("tete", "corps"). Pour une section de coquille, c’est son nom. Utile pour fabriquer un id HTML unique quand la même section est posée deux fois.

section.typechaîne

Le nom du fichier, sans sections/ ni .liquid.

section.settingsobjet

Les réglages de cette instance : les default du schéma, recouverts par les valeurs enregistrées. Voir Les types de réglage.

section.blockstableau

Les blocs, dans l’ordre. Chaque entrée porte id, type et settings. Voir Les blocs.

Attention

Une section ne voit pas les autres sections de la page, ni le HTML déjà rendu. Elles sont rendues en parallèle et concaténées ensuite : rien ne circule de l’une à l’autre, pas même par {% assign %}.

#Les deux façons d’appeler une section

#Depuis un template — une instance par entrée

C’est le cas courant. Le template déclare l’instance, ses réglages et ses blocs :

templates/index.jsonjson
{
  "sections": {
    "nos-services": {
      "type": "prestations",
      "settings": { "titre": "Nos services", "colonnes": "2" },
      "blocks": {
        "b1": { "type": "prestation", "settings": { "nom": "Dépannage" } },
        "b2": { "type": "prestation", "settings": { "nom": "Installation" } }
      },
      "block_order": ["b1", "b2"]
    }
  },
  "order": ["nos-services"]
}

La même section peut être posée plusieurs fois sur une page, sous deux clés différentes, avec des réglages différents. Voir Les templates.

L’en-tête, le pied et la barre d’annonce ne sont dans aucun template : ils doivent apparaître sur toutes les pages. C’est la coquille qui les pose, avec {% section 'nom' %}, et leurs valeurs vivent dans config/settings_data.json sous current.sections.

layout/theme.liquidliquid
{% section 'annonce' %}
{% section 'entete' %}

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

{% section 'pied' %}

Ces sections portent par convention "group": "header" ou "footer" dans leur schéma :

themes/piazza/sections/entete.liquidliquid
{% schema %}
{
  "name": "En-tête",
  "group": "header",
  "settings": [
    { "type": "text", "id": "marque", "label": "Nom affiché", "info": "Vide : le nom du site est utilisé." },
    { "type": "text", "id": "horaires", "label": "Horaires du jour", "default": "Ouvert 7 h – 19 h 30" }
  ]
}
{% endschema %}
Note

group est aujourd’hui purement documentaire : le moteur ne le lit pas. Ce qui décide qu’une section est posée par la coquille, c’est le {% section %} du layout, et rien d’autre. Écris-le quand même — il dit à qui relira le thème où cette section apparaît, et il sera lu le jour où un panneau de réglages existera.

#Les motifs qu’on retrouve dans les quatre thèmes

#Masquer un élément vide plutôt que d’afficher un trou

liquid
{%- if section.settings.texte != blank -%}
  <p class="chapeau">{{ section.settings.texte }}</p>
{%- endif -%}

blank couvre à la fois la chaîne vide et la variable absente. C’est ce qui permet à un client de vider un champ pour faire disparaître un élément, sans laisser une balise vide qui décale la mise en page.

#Une classe pilotée par un select

liquid
<section class="section section-{{ section.settings.fond | default: 'papier' }}">

Le réglage vaut papier, voile, encre ou accent ; la feuille de style définit les quatre classes. Le default: protège du cas où le réglage n’a jamais été renseigné et n’a pas de default dans le schéma.

#Les tirets qui mangent les espaces

{%- if … -%} supprime les blancs autour du tag. Sans eux, une boucle sur douze blocs sème douze lignes vides dans le HTML rendu. Ce n’est pas cosmétique dans un <span> : un blanc de trop dedans se voit à l’écran.

#Réagir à l’envoi d’un formulaire

liquid
{%- if page.demande == 'merci' -%}
  <p class="message message-ok" role="status">
    Merci, votre message est bien arrivé.
  </p>
{%- elsif page.demande == 'erreur' -%}
  <p class="message message-ko" role="alert">
    Le message n'a pas pu être envoyé.
  </p>
{%- endif -%}

page.demande est renseigné après un envoi de formulaire. C’est ce qui permet de remercier sans une ligne de JavaScript : le formulaire poste vers /api/contacts, la route redirige, la page se rend à nouveau.

#Boucler sur les articles du CMS

liquid
{%- if articles.size > 0 -%}
  {%- for article in articles limit: section.settings.nombre -%}
    <h3><a href="{{ article.adresse }}">{{ article.titre }}</a></h3>
    <span class="date">{{ article.date | date_fr }}</span>
  {%- endfor -%}
{%- endif -%}

articles vient du CMS, pas du thème. Un range dans le schéma décide combien on en affiche. Voir Objets.

#Ce qui se passe quand une section échoue

Rien ne tombe en page blanche. La section fautive est remplacée par un commentaire HTML, et le reste de la page rend normalement.

Code source de la page renduehtml
<!-- section inconnue : bandeau-promo -->
<!-- section prestations : tag "for" not closed, line:14, col:1 -->
<!-- section absente : entete -->
CommentaireCause
section inconnue : <type>Le template demande un type dont le fichier n’existe pas.
section absente : <nom>{% section 'nom' %} sans fichier correspondant.
section <type> : <message>La section existe mais son rendu a levé une erreur.
Astuce

Ces commentaires sont le premier endroit à regarder quand un bloc de page a disparu sans explication. Ouvre le code source de la page — pas l’inspecteur, qui ne montre pas toujours les commentaires — et cherche <!-- section.

#Les erreurs fréquentes

Un id de réglage qui ne correspond pas

{{ section.settings.titre }} avec un schéma qui déclare "id": "title" rend du vide, sans erreur. C’est de loin la cause numéro un d’un « réglage qui ne marche pas ».

Un JSON de schéma invalide

La section reste rendable, mais sans aucun réglage : plus de valeurs par défaut, section.settings ne contient que ce que le template a enregistré. Très visible, donc vite corrigé. Voir Le bloc schema.

Deux blocs schema dans le même fichier

Seul le premier est lu, et lui seul est retiré du rendu. Le second sera rendu tel quel et fera échouer la section avec tag "schema" not found.

Un section.settings lu dans un snippet

{% render 'ma-carte' %} n’hérite de rien : le snippet ne voit ni section, ni settings, ni site. Passe ce dont il a besoin en arguments. Voir Snippets.

#La vérification à l’enregistrement

L’API refuse d’écrire un .liquid dont la syntaxe ne s’analyse pas, avec le message de l’analyseur — fichier, ligne, colonne. Le contrôle porte sur la syntaxe, pas sur le sens : {{ nawak }} passe, comme chez Shopify, et rend du vide.

node scripts/theme.mjs pousser✗ sections/hero.liquid — tag "for" not closed, line:14, col:1 [syntaxe]

Le {% schema %} est retiré avant l’analyse, exactement comme au rendu — un schéma au JSON invalide ne bloque donc pas l’enregistrement du fichier.

#Pages voisines