Empat bab sebelumnya nutupin object toko, produk, konten, dan transaksi. Ini bab penutup object: yang struktural (section, block), yang fungsional (form, paginate, filter, search), dan yang khusus file (robots.txt).

Object di bab ini gak mewakili “benda” di toko, tapi mekanisme. section dan block itu soal gimana theme disusun, paginate dan filter soal gimana daftar dipotong dan disaring, form soal gimana input pelanggan ditangani.

section

Isi dan pengaturan section yang lagi dirender. Cuma tersedia di dalam file section dan snippet/block yang dirender dari situ.

  1. id, ID section. Buat section di JSON template, ini ID yang ditulis di file JSON-nya. Buat section statis dari tag section, ini nama file-nya.
  2. settings, pengaturan section, diakses pakai id setting: section.settings.heading.
  3. blocks, array block milik section ini.
  4. location, konteks section-nya: template, section group, atau global.
  5. index, urutan section di lokasinya, mulai dari 1.
  6. index0, urutan mulai dari 0.

Kegunaan paling umum: bikin ID dan class CSS yang unik per section, karena section yang sama bisa dipakai berkali-kali di satu halaman:

<div id="section-{{ section.id }}" class="hero">
  {% style %}
    #section-{{ section.id }} {
      background: {{ section.settings.background_color }};
    }
  {% endstyle %}
  <h2>{{ section.settings.heading }}</h2>
</div>

Kalau kamu nulis .hero { background: ... } tanpa ID, section hero kedua di halaman yang sama bakal ikut warna section pertama.

❌ salah, semua section hero di halaman kena warna yang sama

{% style %}
  .hero { background: {{ section.settings.background_color }}; }
{% endstyle %}

✅ benar, tiap instance punya style-nya sendiri

{% style %}
  #section-{{ section.id }} { background: {{ section.settings.background_color }}; }
{% endstyle %}

section.index berguna buat performa: section pertama di halaman (yang kelihatan tanpa scroll) bisa di-load gambarnya secara eager, sisanya lazy. Bahasannya di 64 Performance Navigasi dan Loading. Object ini dibahas lagi di 26 Sections dan Section Schema.

block

Isi dan pengaturan satu section block (block yang didefinisikan di schema section). Diakses waktu loop section.blocks:

  1. id, ID block. Dibuat dinamis sama Shopify dan bisa berubah, jadi jangan pernah nulis nilai literalnya di kode.
  2. type, tipe block, string bebas yang didefinisikan di schema. Ini yang dipakai buat nentuin markup mana yang dirender.
  3. settings, pengaturan block, block.settings.text.
  4. shopify_attributes, atribut data-* yang dipakai theme editor buat ngenalin block dan dengerin event. Wajib ditaruh di elemen pembungkus block. Di luar theme editor, nilainya kosong.

Maksimal 50 block per section. Pola standarnya:

{% for block in section.blocks %}
  {% case block.type %}
    {% when 'heading' %}
      <h2 {{ block.shopify_attributes }}>{{ block.settings.text }}</h2>
    {% when 'text' %}
      <p {{ block.shopify_attributes }}>{{ block.settings.text }}</p>
    {% when 'button' %}
      <a href="{{ block.settings.link }}" {{ block.shopify_attributes }}>{{ block.settings.label }}</a>
  {% endcase %}
{% endfor %}

Kalau shopify_attributes gak dipasang, merchant gak bisa klik block-nya di preview theme editor buat langsung loncat ke pengaturannya. Theme Check punya aturan buat ngingetin ini.

❌ salah, block gak bisa dipilih dari preview editor

<h2>{{ block.settings.text }}</h2>

✅ benar

<h2 {{ block.shopify_attributes }}>{{ block.settings.text }}</h2>

Catatan: ini object buat section block (block lama yang didefinisikan di dalam section). Theme block yang dibahas di 29 Theme Blocks Mendalam punya cara render berbeda lewat content_for 'blocks', tapi object block-nya mirip.

app

Buat app block dan app embed: cuma punya metafields, yaitu metafield milik app itu. Dipakai app buat nyimpen konfigurasinya. Bahasannya di 28 Blocks.

form

Informasi soal form yang dibikin tag form dari 12 Tags Khusus Theme > form. Cuma tersedia di dalam {% form %} … {% endform %}. Gunanya dua: ngecek hasil submit dan ngisi ulang input kalau ada error.

1. Status

  1. posted_successfully?, true kalau form berhasil dikirim, false kalau ada error. Buat form customer_address selalu true.
  2. errors, object form_errors (dibahah di bawah). Kalau gak ada error, nilainya falsy.
  3. id, ID form.

Pola dasar:

{% form 'contact' %}
  {% if form.posted_successfully? %}
    <p>Pesan terkirim, terima kasih!</p>
  {% endif %}
  {% if form.errors %}
    {{ form.errors | default_errors }}
  {% endif %}
  ...
{% endform %}

2. Nilai Input

Kalau form gagal, nilai yang diketik pelanggan tersimpan di object form biar bisa diisi ulang, jadi mereka gak ngetik dari nol lagi. Properti mana yang ada tergantung tipe form:

  1. email, ada di form kontak, komentar, dan customer.
  2. body, isi pesan form kontak atau isi komentar.
  3. author, nama penulis komentar (cuma new_comment).
  4. first_name, last_name, phone, buat customer dan alamat.
  5. address1, address2, city, province, zip, country, company, cuma form customer_address.
  6. set_as_default_checkbox, ngerender checkbox HTML buat ngeset alamat ini jadi default (cuma customer_address).
  7. name (nickname penerima) dan message, buat form gift card recipient.
  8. password_needed, selalu true.

Pola isi ulang:

{% form 'contact' %}
  <input type="email" name="contact[email]" value="{{ form.email }}">
  <textarea name="contact[body]">{{ form.body }}</textarea>
{% endform %}

form_errors

Error dari form. Object ini bisa di-loop langsung (isinya nama field yang error, misalnya email), dan punya dua array pendamping dengan urutan yang sama:

  1. translated_fields, nama field yang udah diterjemahin (misalnya “Email” atau “Alamat email”).
  2. messages, pesan error yang udah diterjemahin (misalnya “tidak boleh kosong”).

Cara nampilin manual:

{% if form.errors %}
  <ul>
    {% for field in form.errors %}
      <li>{{ form.errors.translated_fields[field] }} {{ form.errors.messages[field] }}</li>
    {% endfor %}
  </ul>
{% endif %}

Cara malas yang udah cukup bagus, pakai filter default_errors:

{{ form.errors | default_errors }}

Filter-filter form dibahas di 19 Filters HTML, URL, Media, Color, dan Font.

paginate

Tersedia di dalam tag paginate dari 11 Tags Perulangan > paginate. Buat bikin navigasi halaman sendiri kalau default_pagination kurang cocok:

  1. current_page, nomor halaman sekarang.
  2. pages, jumlah total halaman.
  3. items, jumlah total item yang di-paginate.
  4. page_size, jumlah item per halaman.
  5. current_offset, jumlah item di halaman-halaman sebelum halaman ini. Berguna buat nampilin “Menampilkan 21–40 dari 100”.
  6. previous, object part buat halaman sebelumnya. nil di halaman pertama.
  7. next, object part buat halaman berikutnya. nil di halaman terakhir.
  8. parts, array part semua bagian navigasi (nomor halaman dan …).
  9. page_param, nama parameter URL-nya. Biasanya page, tapi buat setting product_list dan sejenisnya dikasih kunci unik.

Object part punya title (nomor halaman atau …), url, dan is_link (false buat halaman sekarang dan buat …).

Pola navigasi manual:

{% paginate collection.products by 12 %}
  ...
  <nav>
    {% if paginate.previous %}
      <a href="{{ paginate.previous.url }}">← Sebelumnya</a>
    {% endif %}
    {% for part in paginate.parts %}
      {% if part.is_link %}
        <a href="{{ part.url }}">{{ part.title }}</a>
      {% else %}
        <span>{{ part.title }}</span>
      {% endif %}
    {% endfor %}
    {% if paginate.next %}
      <a href="{{ paginate.next.url }}">Berikutnya →</a>
    {% endif %}
  </nav>
  <p>Menampilkan {{ paginate.current_offset | plus: 1 }}–{{ paginate.current_offset | plus: paginate.page_size | at_most: paginate.items }} dari {{ paginate.items }}</p>
{% endpaginate %}

Object Filtering

Buat storefront filtering, fitur di mana merchant ngatur filter (harga, warna, ukuran, ketersediaan) di app Search & Discovery, dan theme nampilinnya. Object-nya bertingkat: filter punya banyak filter_value.

1. filter

Satu filter, dari collection.filters atau search.filters:

  1. label, nama filter yang dilihat pelanggan, misalnya “Warna”.
  2. type, jenisnya: boolean (ya/tidak, misalnya “Tersedia”), list (daftar pilihan, misalnya warna), atau price_range (rentang harga).
  3. param_name, nama parameter URL-nya, misalnya filter.v.option.color.
  4. presentation, cara nampilinnya. Buat filter warna bisa swatch atau image.
  5. operator, operator logika buat filter boolean dan list (AND atau OR). nil buat tipe lain.
  6. url_to_remove, URL halaman sekarang tanpa filter ini. Buat tombol “hapus filter”.

Buat tipe list:

  1. values, array semua filter_value.
  2. active_values, yang lagi aktif.
  3. inactive_values, yang gak aktif.

Buat tipe boolean:

  1. true_value dan false_value, dua filter_value-nya.

Buat tipe price_range:

  1. min_value dan max_value, filter_value buat batas bawah dan atas yang lagi aktif.
  2. range_max, harga tertinggi di koleksi atau hasil pencarian. Ini batas maksimum slider-nya.

2. filter_value

Satu nilai filter:

  1. label, nama yang dilihat pelanggan, misalnya “Merah”.
  2. value, nilai buat parameter URL, dipasangkan sama param_name.
  3. param_name, nama parameter filter induknya.
  4. active, true kalau lagi aktif.
  5. count, jumlah hasil yang cocok sama nilai ini. Buat nampilin “Merah (12)”.
  6. url_to_add, URL sekarang ditambah nilai ini. Parameter paginasi dibuang otomatis (biar balik ke halaman 1).
  7. url_to_remove, URL sekarang dikurangi nilai ini.
  8. swatch, object swatch (warna atau gambar) kalau presentasinya swatch.
  9. image, object image kalau presentasinya gambar.

Pola dasar filter list:

{% for filter in collection.filters %}
  {% if filter.type == 'list' %}
    <fieldset>
      <legend>{{ filter.label }}</legend>
      {% for value in filter.values %}
        <label>
          <input type="checkbox" name="{{ value.param_name }}" value="{{ value.value }}" {% if value.active %}checked{% endif %}>
          {{ value.label }} ({{ value.count }})
        </label>
      {% endfor %}
    </fieldset>
  {% endif %}
{% endfor %}

Kenapa url_to_add dan url_to_remove itu penting? Karena bikin URL filter secara manual itu rumit banget (harus gabungin semua filter aktif dengan benar, encode karakter, buang paginasi). Shopify udah ngitungin, kamu tinggal pakai. Bahasan lengkapnya di 37 Filtering.

3. filter_value_display

Representasi visual nilai filter (versi lama sebelum swatch): type (misalnya colors) dan value (representasinya). Di theme baru, pakai filter_value.swatch dan filter_value.image.

Hasil pencarian. Tersedia di template search:

  1. performed, true kalau pencarian beneran dijalankan (ada parameter q di URL). Kalau false, tampilin form kosongnya aja.
  2. terms, kata yang dicari.
  3. results, hasilnya. Tiap item bisa article, page, atau product, dan punya properti tambahan object_type buat ngebedain. Wajib di-paginate, maksimal 50 per halaman.
  4. results_count, jumlah hasil.
  5. types, tipe object yang dicari, dari parameter URL type.
  6. filters, array filter yang diatur buat halaman pencarian.
  7. sort_by, default_sort_by (relevance), sort_options (array sort_option dengan name dan value).

Pola dasar:

{% if search.performed %}
  <h1>{{ search.results_count }} hasil untuk "{{ search.terms }}"</h1>
  {% paginate search.results by 24 %}
    {% for item in search.results %}
      {% case item.object_type %}
        {% when 'product' %}
          {% render 'product-card', product: item %}
        {% when 'article' %}
          {% render 'article-card', article: item %}
        {% when 'page' %}
          <a href="{{ item.url }}">{{ item.title }}</a>
      {% endcase %}
    {% else %}
      <p>Gak ada hasil.</p>
    {% endfor %}
    {{ paginate | default_pagination }}
  {% endpaginate %}
{% endif %}

Ada filter highlight buat nyorot kata yang dicari di dalam hasil. Bahasannya di 38 Search dan Predictive Search.

Buat pencarian prediktif, yaitu saran yang muncul sambil ngetik. Object ini cuma ngasih hasil kalau dirender di section lewat Predictive Search API dan Section Rendering API. Kalau dipanggil di render biasa, kosong. Sama polanya kaya recommendations di 14 Objects Produk dan Koleksi > recommendations:

  1. performed, true kalau lagi dirender lewat API itu.
  2. terms, kata yang diketik.
  3. types, tipe yang dicari, dari parameter type.
  4. resources, object predictive_search_resources dengan array products, collections, articles, dan pages.
{% if predictive_search.performed %}
  {% for product in predictive_search.resources.products %}
    <a href="{{ product.url }}">{{ product.title }}</a>
  {% endfor %}
{% endif %}

Cara pasangnya di 38 Search dan Predictive Search.

sort_option

Satu pilihan urutan dari collection.sort_options atau search.sort_options: name (buat ditampilin, misalnya “Harga, rendah ke tinggi”) dan value (buat parameter URL, misalnya price-ascending).

forloop dan tablerowloop

Udah dibahas tuntas di 11 Tags Perulangan > Object forloop. Ringkasnya: forloop punya first, last, index, index0, rindex, rindex0, length, parentloop. tablerowloop punya semua itu plus col, col0, col_first, col_last, dan row.

Object robots.txt

Sekelompok object yang cuma ada di template robots.txt.liquid, file yang ngasih tau mesin pencari halaman mana yang boleh di-crawl. Strukturnya bertingkat:

  1. robots, punya default_groups, array group aturan bawaan Shopify.
  2. group, satu kelompok aturan buat satu crawler: user_agent (object), rules (array rule), dan sitemap (object, atau blank kalau grup ini gak butuh sitemap).
  3. user_agent, punya directive (selalu User-agent) dan value (nama crawler, misalnya * atau Googlebot).
  4. rule, satu aturan: directive (Allow atau Disallow) dan value (path-nya, misalnya /policies/). Bisa ditampilin langsung tanpa nyebut propertinya.
  5. sitemap, punya directive (selalu Sitemap) dan value (URL sitemap, https://toko.myshopify.com/sitemap.xml).

Pola dasarnya ngerender bawaan Shopify apa adanya, terus nambahin aturan sendiri:

{% for group in robots.default_groups %}
  {{- group.user_agent }}
 
  {%- for rule in group.rules -%}
    {{ rule }}
  {%- endfor -%}
 
  {%- if group.sitemap != blank -%}
    {{ group.sitemap }}
  {%- endif -%}
{% endfor %}

Jangan ganti aturan bawaannya, cukup tambahin. Aturan bawaan Shopify udah dioptimasi buat SEO dan ngelindungin halaman kaya checkout dan akun dari crawler. Bahasannya di 25 Template Spesial robots.txt, llms.txt, agents dan 48 SEO Metadata, hreflang, robots.txt.

Ringkasan

  1. section cuma ada di dalam file section, dan section.id wajib dipakai buat bikin ID dan style yang unik karena section yang sama bisa muncul berkali-kali.
  2. section.index mulai dari 1, berguna buat bedain section di atas layar sama yang di bawah.
  3. block.id dinamis dan bisa berubah, jangan ditulis literal. block.shopify_attributes wajib ditaruh di elemen pembungkus biar block bisa diklik di theme editor.
  4. Maksimal 50 block per section, dan block.type yang nentuin markup mana yang dirender.
  5. form cuma ada di dalam {% form %}, punya posted_successfully?, errors, dan nilai input buat diisi ulang. Properti yang ada tergantung tipe form.
  6. form_errors bisa di-loop, dengan translated_fields dan messages yang udah diterjemahin. Atau cukup form.errors | default_errors.
  7. paginate cuma ada di dalam tag paginate, punya parts (array part dengan title, url, is_link), previous, next, dan current_offset buat “menampilkan X–Y dari Z”.
  8. filter punya tiga tipe: boolean, list, price_range, masing-masing dengan properti nilai yang beda (true_value/false_value, values/active_values, min_value/max_value/range_max).
  9. filter_value.url_to_add dan url_to_remove udah ngitungin URL-nya, jangan bikin manual.
  10. search.results campur produk, artikel, dan halaman, bedain pakai object_type, dan wajib di-paginate.
  11. predictive_search cuma terisi kalau dirender lewat Predictive Search API, hasilnya di resources.products/collections/articles/pages.
  12. Object robots.txt bertingkat: robots.default_groups → group → user_agent, rules, sitemap, dan aturan bawaannya jangan diganti, cukup ditambah.

Selesai sudah bahasan object. Bab selanjutnya kita mulai filter, dimulai dari yang paling dasar dan paling sering dipakai: manipulasi teks, hitung-hitungan, dan pengolahan array.