Tipps und Kniffe aus der Praxis

Die Handgriffe, die ein Theme robust machen: Standardwerte, sicheres Verketten, leere Listen, Bilder, Adressen und Beträge.

Für Entwickler

Voraussetzungen

  • Recht: website:write

Ein Theme wird nicht an der Startseite gemessen, die der Entwickler mit gepflegten Daten sieht, sondern an dem Betrieb, der drei Felder leer gelassen hat. Die folgenden Handgriffe kosten je eine Zeile und verhindern genau das.

STANDARDWERTE: `{{ wert | default: "Vorgabe" }}` greift, wenn der Wert fehlt, leer oder falsch ist. ACHTUNG: Auch die Zahl `0` gilt als falsch — für eine Zahl, bei der `0` ein gültiger Wert ist (ein Innenabstand von null etwa), ist `default` das falsche Werkzeug. Prüfen Sie dort auf `== nil`.

SICHER VERKETTEN: Eine Kette über eine fehlende Ebene hinweg bricht NICHT ab, sie ergibt nichts. `{{ opening_hours_sets_by_id[kennung].days[0].label }}` ist also gefahrlos, auch wenn es die Kennung nicht gibt. Das ist bequem — und es heisst zugleich, dass ein Tippfehler im Namen genauso aussieht wie ein leeres Feld.

LEERE LISTEN: Drei Wege, derselbe Zweck — `{% for … %}{% else %}`, `{% if liste == empty %}` und `{% if liste.size > 0 %}`. Der erste ist der kürzeste und fängt zusätzlich den Fall ab, dass es die Liste gar nicht gibt.

BILDER: Bauen Sie ein Teilstück, das die Adresse durch `safe_url` schickt, auf `blank` prüft und `loading="lazy"` setzt. Ein Bild in einem Theme kommt fast immer aus einer Einstellung, also aus Kundendaten.

ADRESSEN: Jede Adresse aus einer Einstellung gehört durch `safe_url` — besonders in einem `style`-Attribut mit `url(…)`. Ein Wert mit einem Anführungszeichen verlässt sonst das Attribut, ein Wert mit `);` die CSS-Regel.

BETRÄGE: Produkte bringen mit `price` bereits einen fertigen Text mit; nehmen Sie den. Rechnen Sie ausnahmsweise selbst, dann mit `price_cents | divided_by: 100.0 | money`. Diese Engine teilt übrigens auch bei `divided_by: 100` mit Nachkommastellen — das Liquid anderer Anbieter täte hier eine Ganzzahldivision und gäbe 48 statt 48,50 aus.

ATTRIBUTE ZUSAMMENSETZEN: `{% capture %}` ist der saubere Weg, ein `style`-Attribut aus mehreren Bedingungen zu bauen, ohne dass Zeilenumbrüche im Attribut landen.

FEHLERSUCHE: `{{ irgendwas | json }}` in einem `<pre>` zeigt in einem Zug, was tatsächlich ankommt — schneller als jedes Ausprobieren einzelner Feldnamen.

Codebeispiele

default — und die Falle mit der Null
Liquid
{%- assign abstand = 0 -%}fehlender Wert: [{{ settings.gibt_es_nicht | default: 1280 }}]Null mit default: [{{ abstand | default: 1280 }}]Null mit Prüfung: {% if abstand == nil %}{% assign abstand = 1280 %}{% endif %}[{{ abstand }}]
Die mittlere Zeile ist der Fehler, den man erst beim Kunden sieht: Ein Redakteur, der den Innenabstand bewusst auf 0 zieht, bekommt trotzdem 1280 zurück. Sobald `0` ein gültiger Wert ist, gehört dort eine Prüfung auf `nil` hin.
Sicher verketten, ohne Absturz
Liquid
[{{ opening_hours_sets_by_id['gibt-es-nicht'].days[0].label }}][{{ products[99].title }}][{{ navigation_menus_by_handle['tippfehler'].items[0].url }}]
Drei Ketten ins Leere, dreimal eine leere Ausgabe, kein Fehler. Das ist beim Bauen angenehm und bei der Fehlersuche tückisch — deshalb gehört in jede solche Kette eine `{% if %}`-Prüfung, sobald daraus ein Attribut oder eine Adresse wird.
Leere Listen: drei Wege, derselbe Zweck
Liquid
{% for satz in opening_hours_sets %}{{ satz.title }} {% else %}keine Sets{% endfor %}
{% if menus == empty %}keine Menüs{% else %}{{ menus.size }} Menüs{% endif %}
{% if products.size > 0 %}{{ products.size }} Gerichte{% endif %}
Der erste Weg fängt zusätzlich ab, dass es die Variable gar nicht gibt — die beiden anderen setzen voraus, dass wenigstens eine leere Liste da ist. In dieser Engine ist das kein Unterschied, bei einer eigenen Variable schon.
snippets/bild.liquid
Liquid
{%- assign quelle = url | safe_url -%}{%- if quelle != blank -%}<img src="{{ quelle }}" alt="{{ alt | escape }}" loading="lazy"{% if breite %} width="{{ breite }}"{% endif %}>{%- else -%}<!-- bild: keine verwendbare Adresse -->{%- endif -%}
Das Teilstück, das man einmal baut und danach überall benutzt: Adresse absichern, auf `blank` prüfen, `alt` maskieren, verzögert laden. Der HTML-Kommentar im `else`-Zweig verrät bei der Fehlersuche im Quelltext, dass eine Adresse abgewiesen wurde.
Und so wird es aufgerufen
Liquid
{% render 'bild', url: products[0].image_url, alt: products[0].title, breite: 800 %}
{% render 'bild', url: 'javascript:alert(1)', alt: 'böse' %}
Der zweite Aufruf zeigt, was die Sicherung leistet: `safe_url` wirft die Adresse weg, das Teilstück gibt den Kommentar aus, und im Markup landet kein `src`. Ohne diese Prüfung stünde dort ein Attribut, das ein Browser ausführen könnte.
Eine Adresse im style-Attribut absichern
Liquid
{%- assign hintergrund = section.settings.hintergrund_url | default: products[0].image_url | safe_url -%}{% if hintergrund != blank %}<div class="buehne" style="background-image:url('{{ hintergrund }}')"></div>{% else %}<div class="buehne buehne--leer"></div>{% endif %}
Der gefährlichste Ort für eine ungeprüfte Adresse. `escape` allein genügt hier NICHT: der Browser macht aus `&#39;` beim Auswerten des Attributs wieder ein Anführungszeichen, und die CSS-Zeichenkette wäre weiterhin zu beenden. Nur ein Wert, der die gefährlichen Zeichen gar nicht enthält, ist in beiden Zusammenhängen sicher — genau das prüft `safe_url`.
Beträge, die stimmen
Liquid
fertig formatiert: {{ products[0].price }}selbst gerechnet: {{ products[0].price_cents | divided_by: 100.0 | money }}mit Aufschlag: {{ products[0].price_cents | times: 1.1 | divided_by: 100.0 | round: 2 | money }}Summe der Karte: {{ products | map: 'price_cents' | sum | divided_by: 100.0 | money }}
Nehmen Sie `price`, wo es geht. Beim Selbstrechnen immer erst rechnen, dann durch 100 teilen, dann formatieren — `money` gibt eine Zeichenkette zurück, mit der sich nicht mehr weiterrechnen lässt.
Ein Attribut mit capture zusammensetzen
Liquid
{%- capture stil -%}--abstand-oben: {{ section.settings.abstand_oben | default: 72 }}px;{%- if section.settings.hintergrund != blank %}--farbe-flaeche: {{ section.settings.hintergrund }};{% endif -%}{%- endcapture -%}<section style="{{ stil }}"></section>
Mit `capture` bauen Sie den Wert in Ruhe zusammen und geben ihn in einer Zeile aus. Die Bindestriche an den Klammern sind hier keine Kosmetik: ohne sie landen Zeilenumbrüche im `style`-Attribut.
Fehlersuche: einmal alles sehen
Liquid
<pre>{{ section.settings | json }}</pre>
<pre>{{ products[0] | json }}</pre>
<pre>{{ navigation_menus | json }}</pre>
Der schnellste Weg zur Antwort auf „wie heisst das Feld noch mal". Denken Sie daran, die Blöcke wieder zu entfernen — sie stehen sonst im Quelltext der Kundenseite.

Wo im Dashboard

/restaurant/[slug]/website/themes/[id]/code

Im Dashboard öffnen