
Shopify Liquid : guide pratique pour les développeurs de thèmes
Liquid, c’est quoi (et pourquoi s’y intéresser) ?
Liquid est le langage de templating de Shopify. Il relie vos données storefront (produits, collections, panier, métachamps) à votre UI de thème (sections, snippets, templates). Liquid s’exécute côté Shopify : c’est rapide, sécurisé et SEO-friendly—pas besoin de backend perso.
En un coup d’œil :
- Objets (sources de données) :
product
,collection
,cart
,blog
,linklists
(navigation),shop
, etc. - Tags (logique/contrôle) :
{% if %}
,{% for %}
,{% section %}
,{% render %}
. - Filtres (format/transform) :
| money
,| image_url
,| times:
,| default:
.
Les briques de base (avec exemples)
1) Sortie et variables
{% assign price = product.price | money %}
<p>{{ product.title }} – <strong>{{ price }}</strong></p>
2) Conditionnels
{% if product.available %}
<button>Ajouter au panier</button>
{% else %}
<span>Rupture de stock</span>
{% endif %}
3) Boucles
<ul>
{% for image in product.images limit: 4 %}
<li><img src="{{ image | image_url: width: 800 }}" alt="{{ image.alt | escape }}"></li>
{% endfor %}
</ul>
4) Filtres utiles au quotidien
money
,money_with_currency
escape
,json
,truncate
,strip_html
image_url
,img_tag
handleize
,downcase
,capitalize
default
,compact
,uniq
Structure d’un thème (façon OS 2.0)
Arborescence typique :
/layout/theme.liquid
/templates/*.json
/sections/*.liquid
/snippets/*.liquid
/assets/* (CSS, JS, images)
/config/*.json (settings_schema.json + presets)
/locales/*.json
- Layouts enveloppent chaque page (
theme.liquid
). - Templates (JSON) définissent quelles sections s’affichent par type de page (
product.json
,collection.json
, etc.). - Sections sont des blocs modulaires et déplaçables.
- Snippets sont des partials réutilisables (prix, média, SKU…).
- Locales gèrent les traductions.
Sections, blocs et réglages
Section minimale
{% schema %}
{
"name": "Bannière hero",
"settings": [
{ "type": "image_picker", "id": "image", "label": "Image de fond" },
{ "type": "text", "id": "heading", "label": "Titre", "default": "Nouveautés" }
],
"blocks": [
{ "type": "button", "name": "CTA", "settings": [{ "type": "url", "id": "link", "label": "Lien" }, { "type": "text", "id": "label", "label": "Libellé", "default": "Découvrir" }] }
],
"presets": [{ "name": "Bannière hero" }]
}
{% endschema %}
<section class="hero">
{% if section.settings.image %}
<img src="{{ section.settings.image | image_url: width: 2400 }}" alt="">
{% endif %}
<h1>{{ section.settings.heading }}</h1>
{% for block in section.blocks %}
{% if block.type == 'button' %}
<a href="{{ block.settings.link }}" class="btn">{{ block.settings.label }}</a>
{% endif %}
{% endfor %}
</section>
- Le schema décrit l’UI dans l’éditeur de thèmes.
- Les blocs ajoutent des sous-composants répétables (CTA, features, FAQ).
- Les presets rendent la section disponible dans Ajouter une section.
Rendu des snippets et composants
- Préférez
{% render 'snippet', arg: value %}
à{% include %}
(scope isolé).
{% render 'price', product: product, show_compare: true %}
Exemple snippets/price.liquid
:
{% assign price = product.price | money %}
{% if show_compare and product.compare_at_price > product.price %}
<span class="price price--sale">{{ price }}</span>
<s class="price price--compare">{{ product.compare_at_price | money }}</s>
{% else %}
<span class="price">{{ price }}</span>
{% endif %}
Métachamps : données sur mesure, markup propre
Utilisez les metafields pour éviter le contenu en dur.
Faits marquants produit (liste de textes) :
{% if product.metafields.custom.highlights %}
<ul class="highlights">
{% for bullet in product.metafields.custom.highlights.value %}
<li>{{ bullet }}</li>
{% endfor %}
</ul>
{% endif %}
Média avec dimensions (fichier) :
{% assign spec_pdf = product.metafields.documents.spec_sheet.value %}
{% if spec_pdf %}
<a href="{{ spec_pdf.url }}" download>Télécharger la fiche technique</a>
{% endif %}
Performance et SEO : quick wins
- Utilisez
image_url
avec des largeurs explicites ; gérezsrcset
viaimg_tag
ou votre balisage. - Lazy-load sous la ligne de flottaison (
loading="lazy"
). - Limitez les boucles
for
et les appelsrender
imbriqués. - Sortez des données structurées (JSON-LD) pour produits/collections.
- CSS/JS minimalistes ; ne chargez que le nécessaire par template.
JSON-LD Produit (minimal) :
<script type="application/ld+json">
{
"@context":"https://schema.org/",
"@type":"Product",
"name": {{ product.title | json }},
"image": {{ product.images | map: 'src' | json }},
"description": {{ product.description | strip_html | truncate: 300 | json }},
"sku": {{ product.selected_or_first_available_variant.sku | json }},
"offers": {
"@type":"Offer",
"priceCurrency": {{ shop.currency | json }},
"price": {{ product.price | divided_by: 100.0 | json }},
"availability": "{{ product.available | default: false | replace: 'true','https://schema.org/InStock' | replace: 'false','https://schema.org/OutOfStock' }}"
}
}
</script>
Panier, checkout et limites de Liquid
- Panier : totalement personnalisable dans le thème.
- Checkout : personnalisations limitées sur les offres standard (couleurs, logo). Pour aller plus loin : Shopify Plus (Checkout Extensibility, UI extensions).
- Pour la logique métier au-delà de Liquid : Shopify Functions/Apps (remises, frais de port, validation).
App blocks et sources dynamiques
- De nombreuses apps proposent des app blocks à ajouter aux templates—sans copier du code.
- Liez les réglages de section à des sources dynamiques (métachamps, traductions, réglages globaux) pour la réutilisation.
Astuces de debug
- Afficher temporairement des valeurs :
<pre>{{ product | json }}</pre>
- Se prémunir de
nil
:
{{ product.vendor | default: "Marque inconnue" }}
- Utiliser Theme Inspector for Liquid (profiling) et Preview avec différents handles.
Patterns fréquents
- Prix & badges : prix barré, % de remise, « Plus que X en stock » (via
variant.inventory_quantity
). - Swatches : variantes groupées par option (« Couleur »), chaque pastille sélectionne une variante.
- Pagination :
paginate
pour blogs/collections. - Fil d’Ariane : collection → produit ; fallback vers collection par défaut ou tous les produits.
Exemple de pagination :
{% paginate collection.products by 24 %}
{% for product in collection.products %}
{% render 'card-product', product: product %}
{% endfor %}
<nav class="pagination">
{% if paginate.previous %}<a href="{{ paginate.previous.url }}">Précédent</a>{% endif %}
<span>{{ paginate.current_page }} / {{ paginate.pages }}</span>
{% if paginate.next %}<a href="{{ paginate.next.url }}">Suivant</a>{% endif %}
</nav>
{% endpaginate %}
Plan en 60 minutes pour une page produit
0–10 min : dupliquez le thème, créez un preset templates/product.json
.
10–30 min : ajoutez sections : galerie média, titre/prix, buy box, onglets/accordéon, produits associés.
30–45 min : câblez les métachamps (points forts, entretien, guide des tailles), badges, JSON-LD.
45–60 min : test variantes, accessibilité (labels, focus), tailles d’image, mobile.
FAQ
Besoin d’un framework JavaScript ?
Pas pour le cœur du storefront. Liquid + un peu de JS (Alpine/vanilla) suffit souvent. Ajoutez un framework seulement si la complexité le justifie.
Réutiliser des sections entre templates ?
Oui. Avec les templates JSON, les sections sont portables. Mettez le contenu dans des métachamps/sources dynamiques pour éviter la duplication.
Meilleure façon d’apprendre Liquid ?
Modifiez une section/snippet existant, imprimez des variables avec | json
, puis créez un snippet réutilisable (prix, badges ou swatches).
CTAs suggérées
- « Découvrez nos services de thèmes Shopify »
- « Consultez l’aide-mémoire Liquid »
- « Obtenez un audit performance de votre thème »