Di 14 Objects Produk dan Koleksi kita bahas yang dijual. Sekarang yang nemenin jualannya: blog, halaman, menu, dan data kustom lewat metafield dan metaobject.

Bab ini dibagi tiga kelompok:

  1. Konten editorial: article, blog, comment, page, user.
  2. Navigasi: linklist dan link.
  3. Data kustom: metafield, metafields, metaobject, dan object-object nilai kaya color, font, rating, money, measurement.

Kelompok ketiga ini yang paling penting buat theme modern, karena metafield itu cara merchant nambahin data apapun ke produk, koleksi, atau halaman tanpa nunggu Shopify nambahin fitur.

article

Satu artikel blog. Tersedia di template article, lewat blog.articles, atau articles['blog-handle/article-handle'].

  1. id, title, handle, url.
  2. content, isi artikel (HTML).
  3. excerpt, kutipan singkat yang diisi merchant.
  4. excerpt_or_content, kutipan kalau ada, kalau nggak ya isi lengkapnya. Ini yang biasanya dipakai di daftar artikel biar gak perlu if.
  5. image, gambar unggulan, object image.
  6. author, nama lengkap penulis (string).
  7. user, object user penulisnya, dengan first_name, last_name, name, email, bio, homepage, image, dan account_owner (true kalau penulisnya pemilik toko).
  8. tags, array tag artikel.
  9. created_at, published_at, updated_at, timestamp.
  10. template_suffix, alternate template-nya.
  11. metafields.
  12. comments, array comment yang udah dipublikasikan. Bisa di-paginate.
  13. comments_count, jumlah komentar yang dipublikasikan.
  14. comments_enabled?, true kalau komentar diaktifkan.
  15. moderated?, true kalau blog induknya moderasi komentar (komentar harus disetujui dulu).
  16. comment_post_url, URL tujuan POST buat komentar baru. Tapi kamu gak perlu ini kalau pakai {% form 'new_comment', article %} yang dibahas di 12 Tags Khusus Theme > form.

Pola daftar artikel:

{% for article in blog.articles %}
  <article>
    {% if article.image %}
      {{ article.image | image_url: width: 600 | image_tag }}
    {% endif %}
    <h2><a href="{{ article.url }}">{{ article.title }}</a></h2>
    <p>{{ article.published_at | date: '%d %B %Y' }} oleh {{ article.author }}</p>
    <p>{{ article.excerpt_or_content | strip_html | truncatewords: 30 }}</p>
  </article>
{% endfor %}

Perhatiin strip_html | truncatewords: 30: karena content itu HTML, kalau dipotong mentah bisa ninggalin tag yang gak ketutup. strip_html dulu baru dipotong. Filter-filternya di 18 Filters String, Math, dan Array.

blog

Satu blog. Tersedia di template blog, atau lewat blogs['handle'].

  1. id, title, handle, url.
  2. articles, array artikel. Bisa di-paginate, dan wajib di-paginate kalau lebih dari 50.
  3. articles_count, jumlah artikel, gak termasuk yang disembunyiin.
  4. all_tags, semua tag dari semua artikel di blog.
  5. tags, sama kaya all_tags (daftar semua tag). Bedanya sama current_tags global: current_tags itu yang lagi aktif sebagai filter.
  6. next_article, artikel berikutnya (yang lebih lama).
  7. previous_article, artikel sebelumnya (yang lebih baru).
  8. comments_enabled? dan moderated?.
  9. template_suffix dan metafields.

Perhatiin arah next_article dan previous_article yang kebalik dari intuisi: “next” itu yang lebih lama, karena blog diurutkan dari yang terbaru. Jadi kalau kamu bikin tombol “Artikel berikutnya”, pikirin dulu maksudnya “berikutnya dalam urutan tampil” atau “yang lebih baru”.

Dua properti ini cuma bernilai di dalam template article (karena butuh tau kamu lagi di artikel mana):

{% if blog.previous_article %}
  <a href="{{ blog.previous_article.url }}">← Lebih baru</a>
{% endif %}
{% if blog.next_article %}
  <a href="{{ blog.next_article.url }}">Lebih lama →</a>
{% endif %}

comment

Satu komentar di artikel:

  1. id.
  2. author, nama penulis komentar.
  3. email, emailnya. Jangan ditampilin ke publik.
  4. content, isi komentar.
  5. created_at dan updated_at.
  6. status, selalu published (karena yang gak dipublikasikan gak ikut dikembalikan).
  7. url, URL artikelnya ditambah #comment-id.

page

Satu halaman statis (About, Contact, FAQ). Tersedia di template page, atau lewat pages['handle']:

  1. id, title, handle, url.
  2. content, isi halaman (HTML).
  3. author.
  4. published_at.
  5. template_suffix dan metafields.

Ingat dari 09 Dasar Liquid > Tipe Data: halaman yang gak ada ngembaliin empty, dan empty itu truthy. Jadi:

❌ salah, blok ini tetap jalan walaupun halamannya gak ada

{% if pages['faq'] %}
  {{ pages['faq'].content }}
{% endif %}

✅ benar

{% unless pages['faq'] == empty %}
  {{ pages['faq'].content }}
{% endunless %}

Ini object buat navigasi. Merchant bikin menu di Shopify admin (Online Store > Navigation), dan theme nampilinnya lewat dua object ini.

Satu menu:

  1. title, judul menu.
  2. handle, handle menu, misalnya main-menu atau footer.
  3. links, array link di menu ini.
  4. levels, jumlah tingkat bersarang di menu (1 = datar, 2 = ada dropdown, 3 = ada mega menu).

Diakses lewat linklists['handle'], atau lebih baik lewat setting bertipe link_list biar merchant bisa milih menu mana yang dipakai. Bahasannya di 30 Settings dan Input Settings.

Satu link di menu:

  1. title, teks link.
  2. url, URL-nya.
  3. handle, handle dari judulnya.
  4. type, jenis tujuannya: article_link, blog_link, catalog_link, collection_link, collections_link, customer_account_page_link, frontpage_link, http_link (link eksternal, atau koleksi per tipe/vendor), metaobject_link, page_link, policy_link, product_link, search_link.
  5. object, object yang ditunjuk link ini, bisa article, blog, collection, metaobject, page, policy, atau product. Ini yang bikin kamu bisa nampilin gambar koleksi di mega menu tanpa query tambahan.
  6. links, array link anak (submenu).
  7. levels, jumlah tingkat di bawah link ini.
  8. data_sharing_opt_out_icon, ikon “Your Privacy Choices” (sebuah <img>) khusus buat link opt-out penjualan data yang otomatis ditambahin Shopify kalau merchant nyalain fitur itu. Hukum privasi negara bagian AS (CCPA/CPRA) mewajibkan ikon ini tampil di sebelah link-nya. nil buat link lain.

Empat properti buat nandain menu yang lagi aktif:

  1. current, true kalau path URL sekarang sama persis dengan URL link. Parameter URL diabaikan, dan URL produk di dalam koleksi (/collections/x/products/y) dianggap sama dengan /products/y.
  2. active, true kalau path URL sekarang sama atau mengandung URL link. Jadi waktu buka /blogs/potion-notions/new-potions, link ke /blogs/potion-notions itu active. Ini buat nyorot kategori induk di menu.
  3. child_current, true kalau ada link anak yang current.
  4. child_active, true kalau ada link anak yang active.

Contoh ngecek jumlah anak:

{% for link in linklists.main-menu.links -%}
  {% if link.links.size > 0 -%}
    - {{ link.title }} ({{ link.links.size }} children)<br>
  {%- else -%}
    - {{ link.title }}<br>
  {%- endif %}
{%- endfor %}

Hasilnya:

- Home<br>
- Catalog (2 children)<br>
- Contact<br>

Pola menu dua tingkat dengan penanda aktif:

<ul>
  {% for link in linklists.main-menu.links %}
    <li class="{% if link.active %}is-active{% endif %}">
      <a href="{{ link.url }}" {% if link.current %}aria-current="page"{% endif %}>
        {{ link.title }}{% if link.data_sharing_opt_out_icon %}{{ link.data_sharing_opt_out_icon }}{% endif %}
      </a>
      {% if link.links.size > 0 %}
        <ul>
          {% for child in link.links %}
            <li><a href="{{ child.url }}">{{ child.title }}</a></li>
          {% endfor %}
        </ul>
      {% endif %}
    </li>
  {% endfor %}
</ul>

Cara bikin navigasi lengkap termasuk mega menu ada di 36 Navigasi dan Menu.

Metafield

Ini bagian terpenting bab ini. Metafield itu data tambahan yang ditempel ke object Shopify. Produk punya kolom bawaan (judul, harga, deskripsi), tapi kalau merchant butuh “bahan”, “cara cuci”, “negara asal”, atau “produk terkait”, itu semua metafield.

Metafield gak bisa dibikin dari Liquid. Cuma bisa lewat Shopify admin (Settings > Custom data) atau lewat app. Liquid cuma baca.

1. Cara Akses

Jalurnya dua lapis: namespace (pengelompokan biar gak bentrok) dan key (nama metafield-nya):

{{ resource.metafields.namespace.key }}

Contoh, metafield directions di namespace information milik produk:

Type: {{ product.metafields.information.directions.type }}
Value: {{ product.metafields.information.directions.value }}

Hasilnya:

Type: single_line_text_field
Value: Take with a meal.

Object yang punya metafields: shop, product, variant, collection, article, blog, page, customer, order, company, company_location, location, market, brand, app, dan remote_product.

Ada jebakan nama: kalau key metafield-nya size, first, atau last, wajib pakai kurung siku. Soalnya tiga nama itu juga filter bawaan Liquid. Dengan notasi titik, Liquid ngembaliin metafield-nya kalau ada, tapi kalau gak ada dia malah nerapin filter-nya ke namespace, jadi size ngembaliin jumlah metafield bukan nilai kosong.

❌ berisiko, kalau metafield-nya gak ada, size jadi filter dan ngembaliin angka

{{ product.metafields.custom.size }}

✅ benar, kurung siku selalu nyari berdasarkan key

{{ product.metafields.custom['size'] }}

2. Object metafield

Tiap metafield punya tiga properti:

  1. type, tipenya (dibahas di bawah).
  2. value, nilainya, bentuknya tergantung tipe.
  3. list?, true kalau ini tipe list (banyak nilai).

Tipe-tipenya:

  1. Teks: single_line_text_field, multi_line_text_field, rich_text_field (mendukung heading, list, link, bold, italic).
  2. Referensi: product_reference (nilainya object product), collection_reference (collection), variant_reference (variant), page_reference (page), file_reference (generic_file atau media buat gambar dan video), url_reference.
  3. Angka: number_integer, number_decimal.
  4. Tanggal: date, date_time, nilainya string yang diformat pakai filter date.
  5. Lainnya: json (object JSON), boolean, color (object color), weight / volume / dimension (object measurement), rating (object rating), money (object money dalam mata uang lokal pelanggan).

Yang penting: buat tipe referensi, value-nya itu object utuh. Jadi product.metafields.custom.related.value itu langsung object product yang bisa kamu ambil title, url, featured_image-nya. Gak perlu query lagi.

Selain baca value mentah, ada filter metafield yang nampilin nilai dalam format HTML yang pas (misalnya rich text jadi HTML, rating jadi bintang). Dibahas di 20 Filters Money, Metafield, Cart, Customer, dan Localization.

3. Metafield Tipe json

value-nya object JSON yang propertinya bisa diakses pakai nama atau indeks, dan bisa di-loop:

Temperature: {{ product.metafields.information.burn_temperature.value.temperature }}
Unit: {{ product.metafields.information.burn_temperature.value['unit'] }}
{% for property in product.metafields.information.burn_temperature.value -%}
  {{ property.first | capitalize }}: {{ property.last }}
{%- endfor %}

Hasilnya:

Temperature: 700
Unit: degrees
Temperature: 700
Unit: degrees
Scale: Fahrenheit

Waktu di-loop, tiap property itu pasangan di mana first = nama kunci dan last = nilainya.

4. Metafield Tipe list

value-nya array yang bisa di-loop:

{% for item in product.metafields.information.combine_with.value -%}
  {{ item.product.title }}
{%- endfor %}

Buat list teks biasa, itemnya bisa diakses langsung pakai indeks:

First item in list: {{ product.metafields.information.pickup_locations.value[0] }}
Last item in list: {{ product.metafields.information.pickup_locations.value.last }}

Cara ngitung panjangnya beda tergantung tipe:

  1. Tipe referensi (list produk, list koleksi): pakai properti count.
  2. Tipe non-referensi (list teks, list angka): pakai filter size.
Number of similar products: {{ product.metafields.information.similar_products.value.count }}
Number of pickup locations: {{ product.metafields.information.pickup_locations.value.size }}

5. Metafield Deprecated

Tipe lama integer, json_string, dan string gak punya properti type, value, list?. Mereka langsung ngembaliin nilainya dan gak kompatibel sama filter metafield. Kalau nemu metafield yang .value-nya kosong padahal ada isinya, kemungkinan tipenya yang lama.

6. metafields dan metafield_namespace

resource.metafields itu object metafields yang ngelompokin per namespace. resource.metafields.custom itu object metafield_namespace. Dua-duanya cuma wadah, gak punya properti sendiri, cuma jalan buat sampai ke metafield-nya.

Metaobject

Kalau metafield itu kolom tambahan di object yang udah ada, metaobject itu tabel baru yang sepenuhnya dibikin merchant. Contoh: “Testimoni” dengan kolom nama, foto, dan kutipan. “Toko fisik” dengan kolom alamat, jam buka, dan peta. Dibikin di Content > Metaobjects.

Strukturnya: metaobject_definition (definisinya, kaya skema tabel) punya banyak metaobject (entri-entrinya, kaya baris tabel).

1. Akses Satu Metaobject

Lewat object global metaobjects, dengan tipe terus handle:

{{ metaobjects.type.handle }}
{{ metaobjects['type']['handle'] }}

Nilai field-nya diakses pakai key field-nya, dan tiap field itu object metafield (jadi ada .value):

{{ metaobjects.testimonials.homepage.title }}
{{ metaobjects['highlights']['washable'].image.value }}

Batasnya 20 handle unik per halaman dan gak bisa di-paginate. Buat lebih banyak, pakai values di bawah.

Kalau metaobject-nya punya capability publishable, yang statusnya draft ngembaliin nil.

2. Loop Semua Entri

Lewat metaobjects.type.values, yang merupakan properti metaobject_definition:

{% for testimonial in metaobjects.testimonials.values %}
  {{ testimonial.author.value }}
{% endfor %}

Maksimal 50 entri per loop, bisa di-paginate sampai 250 per halaman. Ada juga values_count buat jumlah totalnya. Entri berstatus draft dilewatin.

3. Object metaobject

Satu entri punya field-field yang didefinisikan merchant, plus satu properti bawaan system yang dikelompokin biar gak bentrok sama nama field buatan merchant:

  1. system.handle, handle unik entri.
  2. system.id.
  3. system.type, tipe definisinya.
  4. system.url, URL relatif entri, kalau metaobject-nya punya halaman sendiri.

Jadi kalau merchant bikin field bernama id atau url, gak ketuker sama bawaan Shopify.

4. Di Template Metaobject

Metaobject bisa punya halaman sendiri lewat template templates/metaobject/*.json. Di dalam template itu, ada object metaobject yang mewakili entri yang lagi dirender:

{{ metaobject.title.value }}

Bahasannya di 24 Template per Halaman.

Object Nilai

Sekelompok object kecil yang jadi nilai dari setting atau metafield.

1. color

Warna dari setting color atau metafield color. Kalau ditampilin langsung, keluar kode hex:

{{ settings.colors_accent_2 }}

Hasilnya #334fb4. Propertinya:

  1. red, green, blue, komponen 0–255.
  2. alpha, transparansi 0.0–1.0.
  3. hue (0–360), saturation (0–100), lightness (0–100).
  4. chroma (0.0–0.5), buat ruang warna OKLCH.
  5. rgb, string r g b dipisah spasi, buat rgb() CSS modern.
  6. rgba, string r g b / a.
  7. oklch dan oklcha, versi OKLCH-nya.
  8. color_space, srgb atau oklch.

Properti-properti ini yang bikin kamu bisa bikin warna dengan transparansi dari setting:

{% style %}
  .overlay {
    background: rgb({{ settings.colors_accent_1.rgb }} / 0.5);
  }
{% endstyle %}

Ada juga filter warna buat nyampur, nerangin, dan ngegelapin, dibahas di 19 Filters HTML, URL, Media, Color, dan Font. Dan ingat batasan live preview dari 06 Theme Editor dan Code Editor > Live Preview.

2. color_scheme dan color_scheme_group

Dari setting bertipe color_scheme_group. Tiap color_scheme punya id dan settings (object berisi warna-warnanya sesuai definisi di schema). Pola standarnya bikin class CSS per skema:

{% for scheme in settings.color_schemes %}
  .color-{{ scheme.id }} {
    --color-background: {{ scheme.settings.background }};
    --color-text: {{ scheme.settings.text }};
  }
{% endfor %}

Hasilnya:

.color-background-1 {
    --color-background: #FFFFFF;
    --color-text: #121212;
  }
  .color-background-2 {
    --color-background: #F3F3F3;
    --color-text: #121212;
  }
  .color-inverse {
    --color-background: #121212;
    --color-text: #FFFFFF;
  }

Bahasannya di 30 Settings dan Input Settings dan 56 Design dan Color System.

3. font

Font dari setting font_picker:

  1. family, nama keluarga font.
  2. fallback_families, font cadangan.
  3. style, normal atau italic.
  4. weight, ketebalan (400, 700, dan sebagainya).
  5. baseline_ratio, rasio baseline sebagai desimal.
  6. system?, true kalau font sistem (gak perlu di-load).
  7. variants, array font varian lain di keluarga yang sama (bold, italic, dan sebagainya).

Cara load dan pakainya lewat filter font_face, font_url, dan font_modify, dibahas di 19 Filters HTML, URL, Media, Color, dan Font dan 31 Dynamic Sources dan Fonts.

4. rating

Dari metafield rating: rating (nilainya), scale_min, scale_max. Jadi rating 4.5 dari skala 0–5 punya rating = 4.5, scale_min = 0, scale_max = 5.

5. money

Dari metafield money: punya currency (object currency), dan nilainya ditampilin dalam mata uang lokal pelanggan.

6. measurement

Dari metafield weight, volume, atau dimension: type (jenisnya), unit (satuan, misalnya kg), value (angkanya).

Object Kecil Lainnya

1. part

Bagian dari navigasi paginasi, dikembalikan paginate.parts: title (nomor halaman), url, dan is_link (false buat halaman sekarang dan …). Dibahas di 17 Objects Lainnya.

2. parent_relationship

Buat line item bersarang (bundle) di keranjang: parent ngasih line item induknya. Dibahas di 16 Objects Cart, Checkout, Order, dan Customer.

Ringkasan

  1. article.excerpt_or_content buat daftar artikel, dan strip_html dulu sebelum truncatewords.
  2. blog.next_article itu yang lebih lama, previous_article yang lebih baru, dan dua-duanya cuma bernilai di template article.
  3. comment.status selalu published, dan jangan tampilin comment.email.
  4. Halaman yang gak ada ngembaliin empty yang truthy, cek pakai == empty.
  5. linklist itu menu, link itu itemnya. link.object ngasih object tujuannya, link.type ngasih jenisnya, link.links anak-anaknya.
  6. current = URL sama persis, active = URL sama atau mengandung, plus child_current dan child_active buat induknya.
  7. link.data_sharing_opt_out_icon wajib dirender di sebelah link “Your Privacy Choices” buat hukum privasi AS.
  8. Metafield diakses resource.metafields.namespace.key, punya type, value, dan list?. Key size, first, last wajib pakai kurung siku.
  9. Metafield referensi ngembaliin object utuh di value, gak perlu query lagi.
  10. Panjang list: count buat tipe referensi, size buat tipe lain.
  11. Tipe lama integer, json_string, string langsung ngembaliin nilai tanpa .value dan gak kompatibel sama filter metafield.
  12. Metaobject diakses metaobjects.type.handle (maksimal 20 per halaman) atau di-loop lewat metaobjects.type.values (maksimal 50, bisa paginate). Info bawaan ada di system biar gak bentrok sama field merchant.
  13. color ditampilin langsung jadi hex, tapi punya rgb, rgba, oklch buat CSS modern dan komponen red/green/blue/alpha.
  14. color_scheme punya id dan settings, pola standarnya di-loop jadi class CSS per skema.
  15. font punya family, weight, style, system?, dan variants, di-load lewat filter font.

Bab selanjutnya kita ke urusan transaksi: cart dan line_item buat keranjang, customer beserta alamat dan ordernya, order dengan fulfillment dan transaksinya, plus object diskon dan B2B.