Object udah tuntas. Sekarang giliran filter, dimulai dari yang paling sering dipakai: ngolah teks, ngitung angka, dan ngutak-atik array.

Ingat aturan dari 09 Dasar Liquid > Filters: filter ditulis setelah |, nerima parameter setelah :, dan dirantai dari kiri ke kanan. Bab ini bahas filter yang umum di semua Liquid (bukan khusus Shopify), tapi tetap yang bakal kamu tulis tiap hari.

Cara baca sintaks di bab ini: string | append: string artinya filter append nerima string di kiri dan satu parameter string. array | where: string, string artinya nerima array dan dua parameter.

Filter String

1. Ubah Huruf Besar-Kecil

  1. upcase, semua jadi huruf besar. 'hello' | upcase → HELLO.
  2. downcase, semua jadi huruf kecil. 'HELLO' | downcase → hello.
  3. capitalize, huruf pertama kata pertama jadi besar, sisanya jadi kecil. 'this sentence should start with a capitalized word.' | capitalize → This sentence should start with a capitalized word.
  4. camelize, jadi CamelCase. 'variable-name' | camelize → VariableName.

Perhatiin capitalize ngecilin sisanya. Jadi 'iPhone Case' | capitalize jadi Iphone case, bukan IPhone Case.

downcase sering dipakai buat perbandingan yang gak peduli kapital:

{% assign type = product.type | downcase %}
{% if type == 'kaos' %}...{% endif %}

2. Tambah dan Hapus

  1. append, nambahin string di belakang. request.origin | append: product.url → URL absolut.
  2. prepend, nambahin di depan. product.url | prepend: request.origin, hasilnya sama.
  3. remove, hapus semua kemunculan substring. "I can't do it!" | remove: "'t" → I can do it!.
  4. remove_first, hapus kemunculan pertama aja.
  5. remove_last, hapus kemunculan terakhir aja.
  6. replace, ganti semua kemunculan. replace: 'a', 'b'.
  7. replace_first, ganti yang pertama. 'komodo-dragon-scale' | replace_first: '-', ' ' → komodo dragon-scale.
  8. replace_last, ganti yang terakhir.

Buat nggabungin string, append lebih cepat daripada capture, dan ada cara yang lebih cepat lagi pakai echo di dalam tag liquid. Bahasannya di 58 Performance Liquid.

3. Bersihin Spasi dan HTML

  1. strip, buang spasi, tab, dan baris baru di kedua ujung.
  2. lstrip, cuma di kiri.
  3. rstrip, cuma di kanan.
  4. strip_newlines, buang semua baris baru di dalam string.
  5. strip_html, buang semua tag HTML. '<h3>Judul</h3><p>Isi</p>' | strip_html → JudulIsi.
  6. newline_to_br, ganti baris baru \n jadi <br />. Buat nampilin teks dari textarea yang ngehormatin enter.

strip_html wajib dipakai sebelum motong teks yang isinya HTML, kalau nggak tag-nya bisa kepotong di tengah dan ngerusak layout halaman.

4. Potong Teks

  1. truncate: jumlah, potong sampai jumlah karakter, ditambah ... di belakang. Elipsisnya ikut dihitung dalam jumlah karakter. 'How to tell if you're out of invisibility potion' | truncate: 15 → How to tell ....
  2. truncatewords: jumlah, potong sampai jumlah kata, ditambah .... Elipsisnya gak dihitung sebagai kata.

Dua-duanya nerima parameter kedua buat elipsis kustom. Kasih string kosong kalau gak mau elipsis:

{{ article.title | truncate: 15, '--' }}
{{ article.title | truncate: 15, '' }}

Hasilnya:

How to tell i--
How to tell if

Dan ini yang paling penting: tag HTML dihitung sebagai kata oleh truncatewords. Jadi <p> bisa kepotong dan </p>-nya hilang.

❌ salah, tag penutup bisa hilang, layout halaman berantakan

{{ article.content | truncatewords: 15 }}

✅ benar

{{ article.content | strip_html | truncatewords: 15 }}

5. Pecah dan Gabung

  1. split: pemisah, pecah string jadi array. Ini satu-satunya cara bikin array di Liquid. 'health-potion' | split: '-' → ["health", "potion"].
  2. join, gabung array jadi string dipisah spasi. join: ', ' buat pemisah kustom.
  3. slice: mulai atau slice: mulai, panjang, ambil potongan string (atau array) dari indeks 0. Indeks negatif ngitung dari belakang:
{{ collection.title | slice: 0 }}
{{ collection.title | slice: 0, 5 }}
{{ collection.title | slice: -3, 3 }}

Kalau judulnya “Products”, hasilnya:

P
Produ
cts

6. Handle

handleize, ubah string jadi handle sesuai aturan di 09 Dasar Liquid > Handle. Punya alias handle:

{{ product.title | handleize }}
{{ product.title | handle }}

Dua-duanya ngasilin health-potion. Berguna buat bikin ID atau class CSS dari judul.

7. Pluralize

pluralize: tunggal, jamak, pilih bentuk tunggal atau jamak berdasarkan angka:

Cart item count: {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }}

Hasilnya Cart item count: 2 items. Peringatan: ini pakai aturan bahasa Inggris. Buat bahasa Indonesia yang gak punya bentuk jamak, atau bahasa lain yang aturannya beda, pakai sistem terjemahan dengan count yang dibahas di 33 Locales dan Translasi.

Filter Escape dan Encoding

Ini kelompok filter keamanan. Kalau kamu nampilin teks yang diketik orang lain (nama pelanggan, isi komentar, judul produk yang diisi merchant), teks itu bisa berisi <script> atau karakter yang ngerusak HTML.

1. escape

Ubah karakter khusus HTML (<, >, ', &) jadi entitasnya:

{{ '<p>Text to be escaped.</p>' | escape }}

Hasilnya:

&lt;p&gt;Text to be escaped.&lt;/p&gt;

Jadi kalau ada yang ngisi nama <script>alert(1)</script>, yang tampil ya teks itu apa adanya, bukan dieksekusi.

2. escape_once

Sama kaya escape, tapi gak nyentuh karakter yang udah di-escape. Kalau string udah berisi &lt;, escape bakal ngubah &-nya jadi &amp;lt; (double escape), sementara escape_once biarin aja. Pakai ini kalau gak yakin string-nya udah di-escape atau belum.

❌ berisiko, teks dari pengguna ditampilin mentah

<p>{{ comment.content }}</p>

✅ aman

<p>{{ comment.content | escape }}</p>

Ingat juga dari 06 Theme Editor dan Code Editor > Live Preview: escape itu satu-satunya filter yang gak ngerusak live preview setting teks.

3. Filter URL

  1. url_encode, ubah karakter yang gak aman di URL jadi persen-encoded. Spasi jadi +, bukan %20. '[email protected]' | url_encode → test%40test.com.
  2. url_escape, escape karakter yang gak aman di URL. '<p>Health & Love potions</p>' | url_escape → %3Cp%3EHealth%20&%20Love%20potions%3C/p%3E. Perhatiin &-nya gak di-escape.
  3. url_param_escape, sama kaya url_escape plus &. Hasilnya %3Cp%3EHealth%20%26%20Love%20potions%3C/p%3E. Pakai ini buat nilai parameter query, karena & di situ bakal dianggap pemisah parameter.
  4. url_decode, kebalikan url_encode.

4. Base64

  1. base64_encode dan base64_decode. 'one two three' | base64_encode → b25lIHR3byB0aHJlZQ==.
  2. base64_url_safe_encode dan base64_url_safe_decode, versi yang aman buat URL, pakai - dan _ sebagai ganti + dan /.

5. Hash

Buat bikin hash (sidik jari) dari string, biasanya buat verifikasi atau bikin ID unik:

  1. md5, sha1, sha256, blake3, hash biasa.
  2. hmac_sha1: kunci dan hmac_sha256: kunci, hash dengan kunci rahasia (HMAC):
{%- assign secret_potion = 'Polyjuice' | hmac_sha256: 'Polina' -%}
My secret potion: {{ secret_potion }}

Hasilnya 8e0d5d65cff1242a4af66c8f4a32854fd5fb80edcc8aabe9b302b29c7c71dc20. Jarang dipakai di theme biasa, tapi berguna buat integrasi pihak ketiga yang butuh tanda tangan.

Filter Math

Semua nerima angka di kiri:

  1. plus: n, tambah. 4 | plus: 2 → 6.
  2. minus: n, kurang.
  3. times: n, kali.
  4. divided_by: n, bagi. Hasilnya ngikutin tipe pembaginya: dibagi bilangan bulat hasilnya bulat (dibulatkan ke bawah), dibagi desimal hasilnya desimal.
  5. modulo: n, sisa bagi. 12 | modulo: 5 → 2. Berguna buat “tiap item ketiga”.
  6. abs, nilai mutlak. -3 | abs → 3.
  7. ceil, bulatkan ke atas. 1.2 | ceil → 2.
  8. floor, bulatkan ke bawah. 1.8 | floor → 1.
  9. round, bulatkan ke terdekat. 2.7 | round → 3. Dengan parameter: 3.14159 | round: 2 → 3.14.
  10. at_least: n, batasi minimal. 4 | at_least: 5 → 5, 4 | at_least: 3 → 4.
  11. at_most: n, batasi maksimal. 6 | at_most: 5 → 5.

Jebakan divided_by yang sering bikin bingung:

{{ 20 | divided_by: 7 }}
{{ 20 | divided_by: 7.0 }}

Hasilnya:

2
2.857142857142857

❌ salah, persentase diskon jadi 0 karena pembagian bulat

{{ 25 | divided_by: 100 | times: product.price }}

✅ benar, pakai desimal biar hasilnya desimal

{{ 25 | divided_by: 100.0 | times: product.price }}

Buat ngitung persentase diskon dari harga coret:

{% assign discount = product.compare_at_price | minus: product.price | times: 100.0 | divided_by: product.compare_at_price | round %}
Hemat {{ discount }}%

at_least dan at_most berguna buat ngunci nilai dalam rentang, misalnya jumlah kolom grid antara 1 sampai 4: settings.columns | at_least: 1 | at_most: 4.

Filter Array

Ini kelompok yang bikin Liquid bisa ngolah data tanpa perulangan manual.

1. Ambil Item

  1. first, item pertama. Bisa juga pakai notasi titik: collection.products.first.
  2. last, item terakhir. collection.products.last.
  3. size, jumlah item (atau jumlah karakter kalau string). Bisa notasi titik: collection.products.size.

Notasi titik berguna di dalam tag di mana filter gak bisa dipakai:

{% if collection.products.size >= 10 %}
  There are 10 or more products in this collection.
{% else %}
  There are less than 10 products in this collection.
{% endif %}

2. Saring

  1. where: properti, nilai, ambil item yang properti-nya sama dengan nilai:
{% assign polina_products = collection.products | where: 'vendor', "Polina's Potent Potions" %}

Dengan satu parameter aja, where ngambil item yang properti boolean-nya true:

{% assign available_products = collection.products | where: 'available' %}
  1. reject: properti, nilai, kebalikannya, buang item yang cocok.
  2. find: properti, nilai, ambil item pertama yang cocok (bukan array, langsung object-nya):
{% assign product = collection.products | find: 'vendor', "Polina's Potent Potions" %}
{{ product.title }}
  1. find_index: properti, nilai, ambil indeks item pertama yang cocok.
  2. has: properti, nilai, ngembaliin true/false apakah ada item yang cocok.
  3. compact, buang semua item nil. Berguna setelah map ke properti yang bisa kosong.
  4. uniq, buang duplikat. 'invisibility, health, love, health, invisibility' | split: ', ' | uniq | join: ', ' → invisibility, health, love.

Ingat batasan dari 09 Dasar Liquid > Operator Logika dan Perbandingan: contains gak bisa nyari object di array. has dan where itu obatnya.

❌ salah, contains gak bisa nyari object

{% if collection.products contains product %}

✅ benar

{% if collection.products | has: 'id', product.id %}

Tunggu, itu juga salah: filter gak bisa dipakai langsung di dalam if. Yang benar, simpan dulu:

✅ benar beneran

{% assign in_collection = collection.products | has: 'id', product.id %}
{% if in_collection %}

3. Ubah dan Gabung

  1. map: properti, bikin array baru berisi satu properti dari tiap item:
{%- assign product_titles = collection.products | map: 'title' -%}
{{ product_titles | join: ', ' }}

Hasilnya Draught of Immortality, Glacier ice, Health potion, Invisibility potion. 2. concat: array, gabung dua array. Gak buang duplikat, sambung sama uniq kalau perlu:

{%- assign types_and_vendors = collection.all_types | concat: collection.all_vendors -%}
  1. reverse, balik urutan.
  2. sum, jumlahin semua item. Dengan parameter, jumlahin properti tiap item:
Total quantity of all items in cart:
{{ cart.items | sum: 'quantity' }}
Subtotal price for all items in cart:
{{ cart.items | sum: 'final_line_price' | money }}

Hasilnya 2 dan $422.49.

4. Urutkan

  1. sort, urutkan peka kapital (huruf besar duluan) atau numerik. ["Burning", "dried", "Salty"] | sort → Burning, Salty, dried.
  2. sort_natural, urutkan gak peka kapital. Hasilnya Burning, dried, Salty. Jangan dipakai buat angka, karena tiap item diubah jadi string dulu, jadi 10 bakal di depan 9.
  3. Dua-duanya nerima parameter properti buat ngurutin array object: collection.products | sort: 'price'.

Jangan ketuker sama sort_by yang beda total: itu filter URL yang nambahin parameter ?sort_by= ke collection.url:

{{ collection.url | sort_by: 'best-selling' }}

Hasilnya /collections/sale-potions?sort_by=best-selling. Nilainya: manual, best-selling, title-ascending, title-descending, price-ascending, price-descending, created-ascending, created-descending.

❌ salah, sort_by bukan buat ngurutin array

{% assign sorted = collection.products | sort_by: 'price' %}

✅ benar

{% assign sorted = collection.products | sort: 'price' %}

default

Ngasih nilai cadangan kalau variabelnya nil, false, atau empty:

{{ product.selected_variant.url | default: product.url }}

Kalau selected_variant-nya nil, yang keluar product.url.

Perhatiin: string kosong '' itu bukan nil, bukan false, bukan empty, jadi default gak nangkepnya. Ingat aturan truthy/falsy di 09 Dasar Liquid > Truthy dan Falsy.

Ada parameter allow_false: true buat kasus di mana false itu nilai yang sah dan gak boleh diganti:

{%- assign display_price = false -%}
{{ display_price | default: true, allow_false: true }}

Hasilnya false, bukan true.

Dan ingat dari 06 Theme Editor dan Code Editor > Live Preview: default di dalam {% style %} bikin live preview warna rusak, terapin di luar.

date

Ubah timestamp jadi format tanggal lain. Nerima format strftime ala Ruby:

{{ article.created_at | date: '%B %d, %Y' }}

Hasilnya April 14, 2022. Kode format yang paling sering: %d (tanggal 01–31), %m (bulan 01–12), %B (nama bulan penuh), %b (nama bulan singkat), %Y (tahun 4 digit), %y (2 digit), %A (nama hari), %H:%M (jam:menit). Referensi lengkapnya di strftime reference.

Kata kunci 'now' dan 'today' ngasih waktu sekarang:

{{ 'now' | date: '%B %d, %Y' }}

Tapi hati-hati: waktunya itu waktu Liquid terakhir dirender, dan karena ada cache, gak selalu update tiap kunjungan. Jangan dipakai buat countdown atau apapun yang butuh waktu presisi, itu urusan JavaScript.

Format Sadar Bahasa

Daripada nulis %B %d, %Y yang hasilnya selalu bahasa Inggris, pakai parameter format: dengan nama format yang otomatis nyesuaiin bahasa toko:

{{ article.created_at | date: format: 'abbreviated_date' }}

Format bawaannya: abbreviated_date, basic, date, date_at_time, default, on_date (plus short dan long yang deprecated).

Kamu juga bisa bikin format sendiri di file locale di bawah kunci date_formats:

"date_formats": {
  "month_day_year": "%B %d, %Y"
}

Terus dipakai:

{{ article.created_at | date: format: 'month_day_year' }}

Dengan cara ini, tiap bahasa bisa punya format tanggalnya sendiri (Indonesia %d %B %Y, Amerika %B %d, %Y). Bahasannya di 33 Locales dan Translasi.

❌ kurang bagus, format dan nama bulan selalu Inggris

{{ article.published_at | date: '%B %d, %Y' }}

✅ lebih bagus, ngikutin bahasa toko

{{ article.published_at | date: format: 'date' }}

json

Ubah string atau object jadi JSON. Berguna buat ngirim data ke JavaScript:

<script>
  const product = {{ product | json }};
</script>

Gak perlu dibungkus kutip, karena filter json udah nyertain kutipnya dan udah nge-escape kutip di dalamnya.

Satu catatan keamanan: di toko yang dibuat setelah 5 Desember 2017, product | json gak ngeluarin inventory_quantity dan inventory_policy varian, biar bot gak bisa ngintip stok toko. Kalau butuh, akses lewat varian satu-satu.

❌ salah, double kutip

const title = "{{ product.title | json }}";

✅ benar

const title = {{ product.title | json }};

Ringkasan

  1. capitalize ngecilin sisa hurufnya, bukan cuma ngegedein yang pertama.
  2. remove/replace kena semua, remove_first/replace_first cuma yang pertama, _last cuma yang terakhir.
  3. strip_html wajib sebelum truncatewords, karena tag HTML dihitung kata dan bisa kepotong.
  4. truncate ngitung karakter (elipsis ikut dihitung), truncatewords ngitung kata. Parameter kedua buat elipsis kustom.
  5. split itu satu-satunya cara bikin array, join kebalikannya.
  6. escape buat semua teks dari pengguna, escape_once kalau gak yakin udah di-escape.
  7. url_encode ubah spasi jadi +, url_param_escape juga nge-escape & buat nilai parameter query.
  8. divided_by ngikutin tipe pembaginya, bagi dengan 100 hasilnya bulat, bagi dengan 100.0 hasilnya desimal.
  9. at_least dan at_most buat ngunci nilai dalam rentang.
  10. where, reject, find, find_index, has nyaring array berdasarkan properti, dan where dengan satu parameter nyari boolean true.
  11. Filter gak bisa dipakai langsung di dalam if, simpan dulu pakai assign.
  12. map ngambil satu properti, sum bisa ngejumlahin properti, concat gak buang duplikat (pakai uniq).
  13. sort peka kapital, sort_natural nggak (dan jangan buat angka). sort_by itu filter URL, bukan pengurut array.
  14. default cuma nangkep nil, false, empty, bukan string kosong. allow_false: true kalau false itu nilai sah.
  15. date pakai strftime, tapi lebih baik date: format: 'nama' yang sadar bahasa dan bisa dikustom di locale. 'now' gak selalu update karena cache.
  16. json udah nyertain kutip dan nge-escape, dan nyembunyiin stok varian dari product | json.

Bab selanjutnya kita masuk ke filter khas Shopify: bikin tag HTML, URL aset dan CDN, gambar dan video responsif, manipulasi warna, dan load font.