Bagian 1 udah selesai, alat-alat kita lengkap. Sekarang masuk Bagian 2: bahasa Liquid. Di 01 Apa itu Theme Shopify > Cara Kerjanya kita udah lihat sekilas {{ product.title }}, sekarang kita pelajari dari akar.

Liquid itu bahasa template bikinan Shopify, sifatnya open source dan dipakai banyak project lain juga (Jekyll, misalnya). Yang kita pelajari di buku ini adalah variasi Liquid buat theme Shopify, yang punya tag, filter, dan object tambahan khusus buat toko.

Shopify juga punya variasi Liquid lain buat template notifikasi email, Shopify Flow, order printer, dan packing slip, tapi itu gak dibahas di sini.

Apa itu Bahasa Template?

Bahasa template bikin kamu bisa nulis satu cetakan yang isinya konten statis, terus nyisipin informasi dinamis tergantung di mana cetakan itu dirender.

Contoh: kamu bikin satu template produk yang berisi semua atribut standar produk (gambar, judul, harga). Template itu bakal ngerender atribut-atribut tadi dengan isi yang sesuai tergantung produk mana yang lagi dibuka. Satu template, ribuan produk.

Tiga Bahan Utama

Semua kode Liquid itu kombinasi dari tiga hal:

  1. Objects, data yang mau ditampilin. Ditulis di dalam {{ }}.
  2. Tags, logika yang ngatur apa yang harus dilakuin. Ditulis di dalam {% %}.
  3. Filters, pengubah output. Ditulis pakai | setelah object.

Contoh yang gabungin ketiganya:

<title>
  {{ page_title }}
</title>
{% if page_description -%}
  <meta name="description" content="{{ page_description | truncate: 150 }}">
{%- endif %}

Hasilnya:

<title>
  Health potion
</title>
<meta name="description" content="Are you low on health? Well we've got the potion just for you! Just need a top up? Almost dead? In between? No need to worry because we have a ...">

Bedah satu-satu: {{ page_title }} itu object yang ditampilin. {% if page_description %} itu tag yang ngecek apakah deskripsinya ada. | truncate: 150 itu filter yang motong teksnya jadi 150 karakter.

Cara paling gampang ngebedain: {{ }} itu buat nampilin sesuatu, {% %} itu buat ngelakuin sesuatu. Kurung kurawal ganda bakal nyetak ke halaman, kurung persen gak nyetak apa-apa, cuma instruksi.

Objects

Object itu variabel yang bisa kamu pakai buat bangun theme. Jenisnya antara lain:

  1. Sumber daya toko, kaya koleksi atau produk beserta propertinya.
  2. Konten standar yang jadi tulang punggung theme, kaya content_for_header.
  3. Elemen fungsional buat interaktivitas, kaya paginate dan search.

Object bisa mewakili satu nilai atau punya banyak properti. Buat nampilin object, bungkus pakai {{ }}. Buat nampilin propertinya, pakai notasi titik:

{{ product.title }}

Kalau datanya:

{
  "product": {
    "title": "Health potion"
  }
}

Hasilnya:

Health potion

1. Tiga Cara Object Bisa Diakses

Ini penting banget dan sering bikin bingung pemula: gak semua object bisa dipakai di semua tempat.

  1. Global, bisa dipakai di file Liquid manapun. Contohnya shop, settings, request. Kecuali di checkout.liquid dan file asset .liquid.
  2. Di template tertentu, cuma ada di template itu beserta section dan block-nya. Contohnya object product cuma ada di template produk. Kalau kamu pakai product di halaman depan, isinya kosong.
  3. Lewat object induk, dikembalikan sebagai properti object lain. Contohnya object article bisa diakses lewat articles atau blog.

Tiap object punya dokumentasi yang nyebut cara aksesnya. Kita bahas semuanya di 13 Objects Global sampai 17 Objects Lainnya.

❌ salah, product gak ada di halaman koleksi, hasilnya kosong tanpa error

{% comment %} di templates/collection.json {% endcomment %}
<h1>{{ product.title }}</h1>

✅ benar, di halaman koleksi ambil produknya lewat object collection

{% for product in collection.products %}
  <h2>{{ product.title }}</h2>
{% endfor %}

2. Bikin Variabel Sendiri

Pakai tag assign atau capture. Secara sintaks, Liquid memperlakukan variabel sama persis kaya object:

{% assign my_variable = 'My custom string.' %}
{{ my_variable }}

Hasilnya:

My custom string.

Detailnya di 10 Tags Variabel dan Percabangan.

Tags

Tag itu instruksi, bukan konten. Dibungkus {% %}, dan gak nyetak apa-apa ke halaman.

Contoh paling dasar, tag if:

{% if product.available %}
  Price: $99.99
{% else %}
  Sorry, this product is sold out.
{% endif %}

Kalau product.available itu true, hasilnya:

Price: $99.99

Beberapa tag nerima parameter, ada yang wajib ada yang opsional. Contohnya for punya parameter opsional limit buat berhenti di indeks tertentu:

{% assign numbers = '1,2,3,4,5' | split: ',' %}
 
{% for item in numbers limit:2 -%}
  {{ item }}
{% endfor %}

Hasilnya:

1
2

Kalau kamu punya banyak tag berturut-turut, gak perlu nulis {% %} berkali-kali. Ada tag liquid yang bikin kamu bisa nulis banyak tag dalam satu pembungkus. Bahasannya di 10 Tags Variabel dan Percabangan.

Filters

Filter ngubah output dari variabel dan object. Cara pakainya: tulis | setelah object, terus nama filter-nya:

{{ product.title | upcase }}

Kalau judulnya “Health potion”, hasilnya:

HEALTH POTION

Banyak filter nerima parameter setelah tanda titik dua:

{{ product.title | remove: 'Health' }}

Hasilnya:

potion

Dan filter bisa dirantai. Urutannya dari kiri ke kanan, hasil filter pertama masuk ke filter kedua, dan seterusnya:

{{ product.title | upcase | remove: 'HEALTH' }}

Hasilnya:

POTION

Perhatiin: remove-nya nyari 'HEALTH' huruf besar, karena upcase udah jalan duluan. Kalau urutannya dibalik, remove: 'Health' harus huruf biasa. Urutan filter itu penting.

❌ salah, upcase jalan dulu, jadi remove: 'Health' gak nemu apa-apa

{{ product.title | upcase | remove: 'Health' }}

✅ benar, sesuaikan sama urutannya

{{ product.title | remove: 'Health' | upcase }}

Semua filter dibahas di 18 Filters String, Math, dan Array sampai 20 Filters Money, Metafield, Cart, Customer, dan Localization.

Handle

Ini konsep khas Shopify yang bakal kamu temuin di mana-mana.

Object yang mewakili sumber daya toko (produk, koleksi, artikel, blog) punya handle buat mengidentifikasi satu item secara unik. Handle dipakai buat bikin URL sumber daya itu, dan buat ngambil properti-nya. Object lain kaya linklists, links, dan settings juga punya handle.

Gampangnya: handle itu nama “ramah URL” dari sebuah benda. Produk “Health Potion” punya handle health-potion, dan URL-nya /products/health-potion.

1. Aturan Pembuatan Handle

Handle dibuat otomatis dari judulnya, dengan aturan:

  1. Selalu huruf kecil.
  2. Spasi dan karakter khusus diganti tanda hubung -.
  3. Beberapa spasi atau karakter khusus berturut-turut jadi satu tanda hubung.
  4. Spasi atau karakter khusus di awal dibuang.

Handle harus unik. Kalau ada judul yang sama, handle-nya ditambahin angka: dua produk bernama Potion bakal punya handle potion dan potion-1.

Dan ini jebakan yang sering bikin bingung: setelah sumber daya dibuat, ganti judulnya gak ngubah handle-nya. Jadi produk yang dulu dinamain “Ramuan Lama” terus diganti jadi “Ramuan Baru” tetap punya handle ramuan-lama. Handle bisa diubah manual di Shopify admin di bagian Handle atau Edit website SEO, tapi kalau kamu ngerujuk sumber daya pakai handle di kode, rujukannya harus ikut diupdate.

Catatan buat object lain: link di dalam linklists handle-nya dari judulnya dan gak bisa diubah langsung. Setting dari settings_schema.json, section, atau block handle-nya dari properti id-nya.

Ada filter handle buat ngubah string apapun jadi handle:

{{ product.title | handle }}

Kalau judulnya “Health potion”, hasilnya:

health-potion

2. Ngerujuk Pakai Handle

Semua object yang punya handle punya properti handle, misalnya product.handle. Dan kamu bisa ngambil satu object dari object induknya pakai handle dengan dua cara:

  1. Notasi kurung siku [ ], nerima handle dalam tanda kutip, variabel Liquid, atau rujukan object.
  2. Notasi titik ., nerima handle tanpa kutip.
'About us' page URL: {{ pages['about-us'].url }}
Enable product suggestions: {{ settings.predictive_search_enabled }}

Hasilnya:

'About us' page URL: /pages/about-us
Enable product suggestions: true

Kapan pakai yang mana? Kurung siku wajib kalau handle-nya ada tanda hubung (karena pages.about-us bakal dibaca sebagai pages.about dikurangi us) atau kalau handle-nya dari variabel. Notasi titik cukup buat handle sederhana tanpa tanda hubung.

❌ salah, tanda hubung bikin Liquid bingung

{{ pages.about-us.url }}

✅ benar, pakai kurung siku

{{ pages['about-us'].url }}

✅ benar juga, handle dari variabel

{% assign page_handle = 'about-us' %}
{{ pages[page_handle].url }}

Operator Logika dan Perbandingan

Dipakai di tag kondisional (if, unless, case, else):

  1. ==, sama dengan.
  2. !=, tidak sama dengan.
  3. >, lebih besar.
  4. <, lebih kecil.
  5. >=, lebih besar atau sama.
  6. <=, lebih kecil atau sama.
  7. or, kondisi A atau B.
  8. and, kondisi A dan B.
  9. contains, ngecek keberadaan string di dalam string atau array.

1. contains

Bisa dipakai buat ngecek string di dalam array, atau string di dalam string. Tapi gak bisa buat ngecek object di dalam array object:

{% if product.tags contains 'healing' %}
  This potion contains restorative properties.
{% endif %}

❌ salah, contains gak bisa nyari object

{% if collection.products contains product %}

✅ benar, bandingin lewat properti yang berupa string

{% assign handles = collection.products | map: 'handle' %}
{% if handles contains product.handle %}

2. Urutan Evaluasi

Ini yang paling sering bikin bug halus: kalau ada lebih dari satu operator dalam satu tag, dievaluasi dari kanan ke kiri, dan urutan ini gak bisa diubah. Dan tanda kurung () bukan karakter yang valid di dalam tag Liquid. Kalau kamu pakai buat ngelompokin, tag-nya gak bakal dirender sama sekali.

{% unless true and false and false or true %}
  This evaluates to false, since Liquid checks tags like this:
 
  true and (false and (false or true))
  true and (false and true)
  true and false
  false
{% endunless %}

Jadi true and false and false or true dibaca dari kanan: false or true = true, terus false and true = false, terus true and false = false.

❌ salah, tanda kurung bikin tag-nya gak dirender

{% if (a or b) and c %}

✅ benar, pecah jadi variabel dulu

{% assign a_or_b = false %}
{% if a or b %}{% assign a_or_b = true %}{% endif %}
{% if a_or_b and c %}

Tipe Data

Output Liquid bisa salah satu dari enam tipe:

  1. string, deretan karakter dalam kutip tunggal atau ganda. Buat ngecek string kosong, pakai object blank.
  2. number, angka, baik desimal maupun bulat.
  3. boolean, true atau false.
  4. nil, nilai yang tidak terdefinisi. Tag atau output yang ngembaliin nil gak nyetak apa-apa, dan diperlakukan sebagai false. Catatan: string berisi karakter “nil” bukan nil.
  5. array, daftar variabel dengan tipe apapun. Diakses pakai for atau tablerow, atau item tertentu pakai [ ] dengan indeks mulai dari 0. Kamu gak bisa bikin array dari nol cuma pakai Liquid, tapi bisa pakai filter split buat mecah string jadi array.
  6. empty, dikembalikan kalau kamu ngakses object yang terdefinisi tapi gak punya nilai. Contohnya halaman atau produk yang udah dihapus, atau setting tanpa nilai. Bandingin sama empty buat ngecek object-nya ada sebelum ngakses atributnya:
{% unless pages.about-us == empty %}
  <h1>{{ page.title }}</h1>
  <div>
    {{ page.content }}
  </div>
{% endunless %}

Cara bikin array satu-satunya:

{% assign colors = 'red,green,blue' | split: ',' %}
{{ colors[0] }}

Hasilnya red.

Truthy dan Falsy

Semua tipe data harus bisa dievaluasi jadi true atau false. Yang jadi true disebut truthy, yang jadi false disebut falsy.

Aturannya di Liquid sangat sederhana dan sangat berbeda dari JavaScript: cuma nil dan false yang falsy. Semua yang lain truthy. Termasuk:

  1. String kosong '' → truthy.
  2. Angka 0 → truthy.
  3. Array kosong → truthy.
  4. Object kosong (EmptyDrop) → truthy.

Kalau kamu datang dari JavaScript di mana 0 dan '' itu falsy, ini bakal bikin kaget. Akibatnya, kamu harus hati-hati ngecek nilai: nilai yang bentuknya gak sesuai harapan bisa tetap truthy.

Solusinya: string kosong dicek pakai blank, object kosong dicek pakai empty:

{% if settings.featured_potions_title != blank -%}
  {{ settings.featured_potions_title }}
{%- else -%}
  No value for this setting has been selected.
{%- endif %}
{% unless pages.recipes == empty -%}
  {{ pages.recipes.content }}
{%- else -%}
  No page with this handle exists.
{%- endunless %}

Kalau featured_potions_title-nya null dan halaman recipes gak ada, hasilnya:

No value for this setting has been selected.
No page with this handle exists.

❌ salah, string kosong itu truthy, jadi blok ini tetap jalan walau setting-nya kosong

{% if section.settings.heading %}
  <h2>{{ section.settings.heading }}</h2>
{% endif %}

✅ benar, cek pakai blank

{% if section.settings.heading != blank %}
  <h2>{{ section.settings.heading }}</h2>
{% endif %}

Whitespace Control

Tiap baris Liquid, walaupun gak nyetak teks, tetap ngasilin satu baris di output. Jadi file yang penuh tag if dan assign bakal ngasilin HTML yang penuh baris kosong.

Buat ngebuang whitespace itu, tambahin tanda hubung di dalam tag: {%- dan -%}, atau {{- dan -}}. Tanda hubung di sisi kiri buang whitespace sebelum tag, di sisi kanan buang whitespace setelah tag. Boleh cuma satu sisi:

{%- if collection.products.size > 0 -%}
The '{{ collection.title }}' collection contains the following types of products:
 
{% for type in collection.all_types -%}
  {% unless type == blank -%}
    - {{ type }}
  {%- endunless -%}
{%- endfor %}
{%- endif -%}

Hasilnya rapi tanpa baris kosong berlebih:

The 'Sale potions' collection contains the following types of products:
 
- Health
- Health & Beauty
- Invisibility
- Water

Ini bukan cuma soal kerapian. Di beberapa tempat, whitespace itu ngaruh ke tampilan, misalnya di antara elemen inline-block, atau di dalam <pre>. Dan HTML yang lebih kecil berarti halaman yang lebih ringan.

Ringkasan

  1. Liquid itu bahasa template: satu cetakan, data dinamis disisipin waktu dirender.
  2. Tiga bahan: objects {{ }} buat nampilin, tags {% %} buat logika, filters | buat ngubah output.
  3. Gak semua object ada di semua tempat: ada yang global, ada yang cuma di template tertentu, ada yang lewat object induk.
  4. Filter dirantai dari kiri ke kanan, urutannya ngaruh ke hasil.
  5. Handle itu nama ramah-URL yang unik: huruf kecil, spasi jadi -, dan gak berubah walaupun judulnya diganti.
  6. Rujuk pakai handle lewat [ ] kalau ada tanda hubung atau dari variabel, notasi titik cuma buat handle sederhana.
  7. contains cuma buat string di string atau string di array, bukan object di array.
  8. Operator dievaluasi dari kanan ke kiri dan tanda kurung dilarang. Pecah jadi variabel kalau butuh pengelompokan.
  9. Enam tipe data: string, number, boolean, nil, array, empty. Array cuma bisa dibikin lewat split.
  10. Cuma nil dan false yang falsy. String kosong, 0, dan array kosong itu truthy. Cek string pakai blank, cek object pakai empty.
  11. Tiap baris Liquid ngasilin baris output, pakai {%- dan -%} buat buang whitespace.

Bab selanjutnya kita bedah tag-tag pertama: assign, capture, echo, increment, decrement, tag liquid, dan percabangan if, unless, case, else.