Di 28 Blocks kita kenal tiga jenis block. Sekarang kita bedah yang paling powerful: theme block, dari bikin file pertamanya sampai trik closest yang bikin satu block bisa dipakai di mana aja.

Theme block itu block yang didefinisikan di level theme, sebagai file Liquid sendiri di /blocks. Bedanya sama section block dari 28 Blocks > Section Block Yang Paling Sederhana: bisa dipakai di banyak section, dan bisa bersarang di dalam theme block lain buat bikin hierarki.

Ini arsitektur yang dipakai theme Shopify terbaru (Horizon dan keluarganya), di mana section-nya cuma wadah dan semua konten disusun dari theme block yang ditumpuk dan disarangin.

Quick Start: Block Pertama

Kita bikin block teks yang bisa dipakai di section manapun.

1. Bikin Folder dan File

Kalau theme belum punya folder /blocks, bikin di root. Terus bikin blocks/text.liquid.

2. Tulis Markup, Aset, dan Schema

Satu file theme block berisi tiga hal yang sama kaya section: markup, aset opsional (stylesheet/javascript), dan schema wajib:

<div class="text-block text-{{ block.settings.alignment }}">
  {{ block.settings.text }}
</div>
{% stylesheet %}
  .text-left {
    text-align: left;
  }
  .text-center {
    text-align: center;
  }
  .text-right {
    text-align: right;
  }
{% endstylesheet %}
{% schema %}
{
  "name": "Text",
  "settings": [
    {
      "type": "richtext",
      "id": "text",
      "label": "Text"
    },
    {
      "type": "text_alignment",
      "id": "alignment",
      "label": "Alignment"
    },
  ],
  "presets": [
    { "name": "Text" },
    {
      "name": "Content",
      "settings": {
        "text": "<p>Hello, world!</p>"
      }
    }
  ]
}
{% endschema %}

3. Object yang Bisa Dipakai

Theme block punya akses ke:

  1. block, properti dan setting block ini. Di contoh, block.settings.text dan block.settings.alignment.
  2. section, section yang ngerender block ini.
  3. Semua object global.

Dan gak bisa: akses variabel yang dibikin di luar block, atau nerima variabel kaya snippet. Ini beda mendasar yang udah dibahas di 28 Blocks > Theme Block vs Snippet.

4. Preset Itu Wajib Buat Muncul di Editor

Theme block cuma muncul di pemilih block theme editor kalau punya presets. Tanpa preset, block-nya ada tapi merchant gak bisa nambahin. Satu block boleh punya banyak preset, di contoh ada “Text” (kosong) dan “Content” (udah ada isinya).

❌ block gak muncul di pemilih block

{
  "name": "Text",
  "settings": [ ... ]
}

✅ block muncul

{
  "name": "Text",
  "settings": [ ... ],
  "presets": [ { "name": "Text" } ]
}

5. Pakai di Section

Setelah block ada, section harus opt-in buat nerima theme block. Dua hal: render pakai {% content_for 'blocks' %}, dan tambahin @theme di schema:

<div class="custom-section color-{{ section.settings.color_scheme }}">
  {% content_for 'blocks' %}
</div>
{% schema %}
{
  "name": "Custom section",
  "blocks": [{ "type": "@theme" }, { "type": "@app" }],
  "settings": [
    {
      "type": "header",
      "content": "Color"
    },
    {
      "type": "color_scheme",
      "id": "color_scheme",
      "label": "Color scheme",
      "default": "scheme-1"
    }
  ],
  "presets": [
    {
      "name": "Custom section"
    },
    {
      "name": "Heading and text",
      "blocks": [
        {
          "type": "group",
          "settings": {
            "color_scheme": "scheme-3"
          },
          "blocks": [
            {
              "type": "text",
              "settings": {
                "text": "<h1>Image with text</h1>"
              }
            },
            {
              "type": "text",
              "settings": {
                "text": "<p>Pair text with an image to focus on your chosen product, collection, or blog post.</p>"
              }
            }
          ]
        }
      ]
    }
  ]
}
{% endschema %}

Ingat aturan dari 28 Blocks: section cuma bisa pakai section block atau theme block, gak dua-duanya.

Perhatiin preset “Heading and text”: dia nyusun block group yang di dalamnya ada dua block text. Ini kekuatan theme block: section preset bisa ngerakit block bersarang jadi layout siap pakai.

6. Block Bersarang

Theme block bisa nerima theme block dan app block lain sebagai anak. Caranya sama persis kaya section: blocks di schema dan content_for 'blocks' di markup. Ini block group:

<div
  class="group-block color-{{ block.settings.color_scheme }}"
>
  {% content_for 'blocks' %}
</div>
{% schema %}
{
  "name": "Group",
  "blocks": [{ "type": "@theme" }, { "type": "@app" }],
  "settings": [
    {
      "type": "header",
      "content": "Color"
    },
    {
      "type": "color_scheme",
      "id": "color_scheme",
      "label": "Color scheme",
      "default": "scheme-1"
    }
  ],
  "presets": [
    {
      "name": "Group"
    },
    {
      "name": "Column",
      "settings": {
        "color_scheme": "scheme-3"
      },
      "blocks": [
        {
          "type": "text",
          "settings": {
            "text": "<h3>Hello, world!</h3>"
          }
        },
        {
          "type": "text",
          "settings": {
            "text": "<p>How's it going?<\/p>"
          }
        }
      ]
    }
  ]
}
{% endschema %}

Preset “Column” nyarangin dua block text yang kita bikin tadi. Isi block-nya dirender oleh content_for 'blocks' sesuai urutan yang disimpan di template JSON, mekanisme yang sama kaya section.

Batas kedalaman sarangnya 8 tingkat, gak termasuk section. Dan theme block gak bisa definisi block lokal di blocks-nya, cuma bisa ngerujuk @theme, @app, atau nama theme block lain.

Schema Theme Block

Aturannya sama kaya schema section dari 26 Sections dan Section Schema > Tag schema: satu {% schema %} per file, JSON valid, gak boleh di dalam tag lain, gak ngeluarin apa-apa. Atributnya lebih sedikit dari section:

1. name

Judul block di theme editor. Dan judul dinamis berlaku juga di sini: kalau ada setting dengan id heading, title, atau text (sesuai urutan prioritas itu), nilainya dipakai sebagai judul di sidebar. Block “Text” dengan setting id: "text" berisi “Welcome to our store” bakal tampil sebagai “Welcome to our store” di sidebar.

2. settings

Setting block, diakses lewat block.settings. id harus unik di dalam block. Semua tipe setting di 30 Settings dan Input Settings.

3. blocks

Block anak yang diterima:

  1. @app, nerima app block.
  2. @theme, nerima semua theme block di /blocks.
  3. Nama block tertentu, misalnya {"type": "slide"}, cuma nerima block itu.
{
  "name": "Slideshow",
  "blocks": [{"type": "@app"}, {"type": "slide"}]
}

Anak-anaknya dirender pakai {% content_for 'blocks' %}. Dan trik block yang direkomendasikan dari 26 Sections dan Section Schema > 8. Block yang Direkomendasikan berlaku juga: @theme plus nama block tertentu bikin block itu tampil duluan di pemilih.

4. presets

Konfigurasi siap pakai yang dipilih merchant di pemilih Add block. Atributnya sama kaya preset section: name (wajib, disimpan di template JSON), category, settings, dan blocks (anak-anak dengan type, settings, opsional name). Preset diurutkan abjad, bisa dikelompokkan, dan preview-nya dibikin otomatis.

Yang bikin preset block powerful: preset bisa ngerujuk theme block lain dan nyusunnya dalam konfigurasi apapun. Block slide yang preset-nya udah berisi block text:

{% schema %}
{
  "name": "Slide",
  "blocks": [{"type": "@app"}, {"type": "@theme"}],
  "settings": [
    {
      "type": "image_picker",
      "id": "image",
      "label": "Background image"
    },
    {
      "type": "color_background",
      "id": "background",
      "label": "Background color"
    }
  ],
  "presets": [
    {
      "name": "Slide",
      "category": "Banners",
      "settings": {
        "background": "#000000"
      },
      "blocks": [
        {
          "type": "text",
          "settings": {
            "text": "This is a slide!"
          }
        }
      ]
    }
  ]
}
{% endschema %}

5. tag

Bawaannya block dibungkus <div> dengan ID unik:

<div id="shopify-block-[id]" class="shopify-block">
  // Output of the block content
</div>

tag ngubah elemennya. Bedanya sama section: tag di block nerima string apapun sampai 50 karakter, termasuk elemen kustom, bukan cuma daftar tetap:

{
  "name": "Image",
  "tag": "picture"
}

Hasilnya <picture id="shopify-block-[id]" class="shopify-block">.

6. Tanpa Pembungkus: tag null

Buat kasus lanjutan di mana kamu butuh kontrol penuh atas elemen dan atributnya, misalnya tag yang ditentuin dari setting (h1/h2/h3), set "tag": null. Shopify gak ngebungkus block-nya, langsung ngeluarin isinya:

<{{ block.settings.tag }} class="heading" {{ block.shopify_attributes }}>
  ...
</{{ block.settings.tag }}>
{% schema %}
{
  "name": "Heading",
  "tag": null,
  "settings": [
    {
      "type": "select",
      "id": "heading_size",
      "label": "Heading size",
      "options": [
        {
          "value": "h3",
          "label": "Small"
        },
        {
          "value": "h2",
          "label": "Medium"
        },
        {
          "value": "h1",
          "label": "Large"
        }
      ]
    }
  ]
}
{% endschema %}

Tapi ada dua syarat keras buat tag: null:

  1. File-nya harus punya tepat satu elemen HTML level atas. Theme editor mindahin seluruh markup block waktu merchant ngurutin ulang, dan kalau ada dua elemen level atas, satunya bakal jadi yatim piatu.
  2. Elemen level atas itu wajib dikasih {{ block.shopify_attributes }}. Biasanya Shopify nambahin otomatis di pembungkusnya, tapi karena pembungkusnya gak ada, kamu harus nambahin sendiri. Tanpa itu, block gak bisa dikenali theme editor.

❌ salah, dua elemen level atas dan gak ada shopify_attributes

<h2 class="heading">{{ block.settings.text }}</h2>
<p class="subheading">{{ block.settings.sub }}</p>
{% schema %}{ "name": "Heading", "tag": null }{% endschema %}

✅ benar, satu elemen level atas dengan atributnya

<div class="heading-group" {{ block.shopify_attributes }}>
  <h2>{{ block.settings.text }}</h2>
  <p>{{ block.settings.sub }}</p>
</div>
{% schema %}{ "name": "Heading", "tag": null }{% endschema %}

7. class

Nambahin class ke pembungkus, di samping shopify-block:

{
  "name": "Slide",
  "class": "slide"
}

Hasilnya <div id="shopify-block-[id]" class="shopify-block slide">.

Static Block

Sejauh ini block dirender dinamis pakai content_for 'blocks': merchant bisa nambah, hapus, urutin. Static block itu block yang dirender statis di Liquid pakai content_for 'block' (tunggal), dengan tipe dan ID yang kamu tentuin. Gunanya:

  1. Ngasih struktur buat desain yang butuh block yang gak boleh dipindah atau dihapus merchant.
  2. Render bersyarat (di dalam if atau for), yang gak bisa dilakuin block dinamis.

Merchant tetap bisa ngatur setting static block, dan bisa nyembunyiin, cuma gak bisa ngehapus atau mindahin.

1. Statis vs Dinamis

Perbandingannya:

  1. Bisa disembunyiin dan diatur: dua-duanya.
  2. Bisa diurutin ulang (drag and drop): cuma dinamis.
  3. Bisa dihapus atau diduplikasi: cuma dinamis.
  4. Bisa dirender bersyarat atau di dalam loop: cuma statis.
  5. Harus ada di preset biar ditambahin: cuma dinamis. Statis selalu di-parse.
  6. Dihitung di max_blocks: cuma dinamis.

2. Cara Render

{% content_for "block", type: "type", id: "id" %}
  1. type, nama theme block yang ada di /blocks.
  2. id (wajib), pengenal unik di dalam section atau block induknya. Bisa string deskriptif apapun. Wajib karena bisa ada banyak static block bertipe sama, dan Shopify gak pernah bikin ID buat static block, kamu yang nentuin.

Ada perubahan aturan yang menyertai fitur ini: ID block gak perlu unik di seluruh section lagi, cukup unik di induk langsungnya. Jadi static block dengan ID card bisa dipakai di banyak tempat di section yang sama.

3. Ngirim Data

Sama kaya theme block biasa, static block punya akses ke dynamic source dari section dan block induknya. Tapi static block juga bisa nerima data sembarang lewat parameter, kaya snippet:

{% content_for "block", id: "slide-1", type: "slide", color: "#111" %}

Di dalam block, akses pakai nama yang sama:

<h2 style="color: {{ color | default: 'green' }};">
  Shopify
</h2>

Ini satu-satunya cara “ngirim variabel” ke theme block, dan cuma buat static block.

4. Render Bersyarat

Waktu static block dirender di dalam if, Shopify ngedeteksinya dan nampilin ikon mata bertitik di sidebar theme editor biar merchant tau block itu bersyarat. Contoh: kontrol slideshow yang cuma muncul kalau slide-nya lebih dari satu:

<div id="slideshow-{{ section.id }}">
  <div class="slideshow__slides">
    {% content_for "blocks" %}
  </div>
  {% if section.blocks.size > 1 %}
    {% content_for "block", type: "_slideshow-controls", id: "static-slideshow-controls" %}
  {% endif %}
</div>
{% schema %}
  {
    "name": "Slideshow",
    "class": "section--group",
    "blocks": [{ "type": "_slide" }, { "type": "_slideshow-controls" }]
  }
{% endschema %}

Perhatiin: slide-nya dinamis (content_for "blocks"), kontrolnya statis dan bersyarat. Merchant bebas nambah slide, tapi kontrolnya selalu di bawah dan gak bisa dihapus.

5. Static Block di Preset

Static block boleh disertakan di preset buat nimpa nilai setting-nya. Butuh dua kunci tambahan: id (sesuai ID di Liquid) dan static: true.

Kalau gak disertakan di preset, static block tetap ditambahin otomatis dengan setting default waktu section atau block induknya ditambahin. Jadi menyertakannya di preset itu cuma buat ngatur nilai awalnya.

Contoh baris yang bisa dilipat, dengan summary dan ikon sebagai static block karena hubungannya tetap (baris selalu punya summary dan ikon di atas):

{% content_for "block", type: "collapsible-row-summary", id: "collapsible-row" %}
<div>
  {% content_for "blocks" %}
</div>
{% schema %}
{
  "name": "Collapsible row",
  "tag": "details",
  "class": "details",
  "blocks": [{ "type": "@theme" }, { "type": "@app" }],
  "settings": [],
  "presets": [
    {
      "name": "Collapsible row",
      "blocks": [
        {
          "type": "collapsible-row-summary",
          "static": true,
          "id": "collapsible-row",
          "blocks": [
            {
              "type": "icon",
              "id": "collapsible-row-icon",
              "static": true,
              "settings": {
                "icon": "check_mark",
                "size": {
                  "width": "22px"
                }
              }
            }
          ]
        },
        {
          "type": "group",
          "blocks": [
            {
              "type": "heading"
            },
            {
              "type": "text"
            }
          ]
        }
      ]
    }
  ]
}
{% endschema %}

6. Static Block di Data JSON

Di template JSON, static block disimpan dengan dua ciri:

  1. static: true nandain block-nya statis.
  2. ID-nya gak ada di block_order, karena gak bisa diurutin merchant. Urutannya ditentuin posisi di kode Liquid relatif terhadap block dinamis.
{
  "sections": {
   "custom_section": {
     "type": "custom-section",
     "blocks": {
       "collapsible_row": {
         "type": "collapsible-row",
         "settings": {},
         "blocks": {
           "collapsible-row-summary": {
             "type": "collapsible-row-summary",
             "static": true,
             "settings": {
               "summary": "Collapsible row"
             },
             "blocks": {
               "collapsible-row-icon": {
                  "type": "icon",
                  "static": true,
                  "settings": {
                  "icon": "check_mark",
                  "size": {
                    "width": "22px"
                  }
                }
               }
             },
             "block_order": []
           }
         },
         "block_order": []
       }
      },
      "block_order": ["collapsible_row"],
      "settings": {
        "direction": "column",
        "justify_content": "flex-start",
        "full_width": false
      }
   }
  },
  "order": ["custom_section"]
}

Perhatiin block_order di collapsible_row itu kosong walaupun ada block collapsible-row-summary di dalamnya, karena block itu statis.

Targeting: Block Mana yang Boleh

Theme block targeting ngatur block mana yang bisa dipakai di sebuah section (atau block). Dua pilihan:

1. Terima Semua

@theme di blocks schema:

{% content_for 'blocks' %}
{% schema %}
{
  "name": "Section",
  "blocks": [{"type": "@theme"}]
}
{% endschema %}

2. Terima yang Tertentu

Rujuk block-nya secara eksplisit. Section slideshow yang cuma nerima block slide:

{% content_for 'blocks' %}
{% schema %}
{
  "name": "Slideshow",
  "blocks": [{"type": "slide"}]
}
{% endschema %}

Tapi ada jebakan: block yang punya preset itu bawaannya tersedia di semua section dan block yang nerima @theme. Jadi block slide di atas tetap muncul di pemilih block section lain yang pakai @theme, padahal slide gak masuk akal di luar slideshow.

3. Private Block

Solusinya: awali nama file block dengan garis bawah. slide.liquid jadi _slide.liquid. Block berawalan _ dikecualikan dari pemilih block di semua section dan block yang pakai @theme. Buat makainya, section harus nyebut nama file-nya secara eksplisit:

{% schema %}
{
  "name": "Slide",
  "presets": [{"name": "Slide"}]
}
{% endschema %}
{% content_for 'blocks' %}
{% schema %}
{
  "name": "Slideshow",
  "blocks": [{"type": "_slide"}]
}
{% endschema %}

Sekarang _slide cuma muncul di slideshow. Ini pola yang sangat umum di theme modern: block umum (text, image, button) tanpa awalan, block khusus (_slide, _slideshow-controls, _product-card) pakai awalan.

❌ salah, block slide nongol di pemilih block semua section

blocks/slide.liquid

✅ benar, cuma bisa dipakai section yang nyebut namanya

blocks/_slide.liquid

Dynamic Sources dan closest

Ini bagian yang bikin theme block beneran bisa dipakai di mana aja. Bahasan dynamic source secara umum ada di 31 Dynamic Sources dan Fonts, di sini kita fokus ke cara theme block ngambil datanya.

Dynamic source bikin merchant bisa nyambungin setting ke data dari produk, koleksi, blog, halaman, metafield, dan metaobject. Setting theme block bisa nyambung ke data dari empat sumber:

  1. Template, sumber daya halaman yang lagi dirender (produk di halaman produk).
  2. Section, setting sumber daya (produk, koleksi) di schema section induk.
  3. Block, setting sumber daya di block leluhur manapun.
  4. Liquid, sumber daya yang dikirim eksplisit ke tag content_for.

Akses biasanya:

// Template resource
{{ product }}
{{ collection }}
// Section settings
{{ section.settings.featured_product }}
// Block settings
{{ block.settings.collection }}

Masalahnya: theme block itu bisa dipakai ulang dan disarangin di mana aja, jadi gak selalu bisa tau duluan datanya datang dari mana. Block “harga” bisa ada di halaman produk (datanya dari template), di section produk unggulan (dari section), atau di dalam block kartu produk (dari block induk).

1. closest

Solusinya object closest dari 13 Objects Global > closest: ngasih sumber daya terdekat dari tipe tertentu, dari manapun asalnya. Urutan pencariannya, dari yang paling dekat:

  1. Setting produk di block yang sama.
  2. Setting produk di block induk.
  3. Setting produk di section.
  4. Produk dari template.

Contoh: section “Image banner” punya block “Product card” (dengan setting produk = Sunglasses) yang isinya block Media, Title, dan Price. Ketiganya nyambung ke closest.product, yang sekarang Sunglasses dari setting Product card. Kalau Sunglasses dihapus dari Product card, ketiga block itu tetap nunjuk ke setting Product card (yang sekarang kosong), jadi nampilin placeholder. Kalau T-shirt dipilih, ketiganya nampilin T-shirt.

Catatan: closest.<tipe> cuma bisa diakses lewat setting theme, sebagai nilai konfigurasi setting. Bukan object yang kamu panggil langsung di Liquid sembarangan.

2. Di Preset

Nyambungin setting ke sumber daya terdekat lewat preset, pakai sintaks {{ closest.<tipe> }} sebagai string di JSON. Nilai yang tersedia:

  1. {{ closest.product }}
  2. {{ closest.collection }}
  3. {{ closest.article }}
  4. {{ closest.blog }}
  5. {{ closest.page }}
  6. {{ closest.metaobject[<tipe_definisi>] }}

Block harga dengan setting produk yang preset-nya nunjuk ke closest.product:

{{ block.settings.product.price | default: 1999 }}
{% schema %}
{
  "name": "Product (price)",
  "class": "price-block",
  "settings": [{
    "type": "product",
    "id": "product",
    "label": "Product"
   }],
  "presets": [{
    "name": "Product (price)",
    "settings": {
      "product": "{{ closest.product }}"
    }
  }]
}
{% endschema %}

Perhatiin: kode Liquid-nya cuma baca block.settings.product, gak peduli produknya dari mana. Yang nentuin dari mana itu nilai setting "{{ closest.product }}" di preset. Kalau merchant mau, mereka bisa ganti setting ini ke produk tertentu lewat theme editor.

Block kartu yang ngerakit tiga block anak, semuanya nunjuk ke closest.product:

{% schema %}
{
  "name": "Card",
  "blocks": [{"type": "@theme"}],
  "presets": [
    {
      "name": "Product Card",
      "blocks": [
        {
          "type": "group",
          "blocks": [
            {
              "type": "text",
              "settings": {
                "text": "<p>{{ closest.product.title }}</p>"
              }
            },
            {
              "type": "price",
              "settings": {
                "product": "{{ closest.product }}"
              }
            },
            {
              "type": "product-medias",
              "settings": {
                "product": "{{ closest.product }}"
              }
            }
          ]
        }
      ]
    }
  ]
}
{% endschema %}

Perhatiin "<p>{{ closest.product.title }}</p>" di block text: setting teks bisa nyambung ke properti sumber daya terdekat, bukan cuma ke object-nya. Setelah preset disisipkan, data disimpan di template JSON apa adanya, dengan string {{ closest.product }} di dalamnya:

{
  "sections": {
    "custom_section_1": {
      "type": "custom-section",
      "blocks": {
        "group_1": {
          "blocks": {
            "text_1": {
              "type": "text",
              "settings": {
                "text": "<p>{{ closest.product.title }}</p>"
              }
            },
            "price_1": {
              "type": "price",
              "settings": {
                "product": "{{ closest.product }}"
              }
            },
            "product_medias_1": {
              "type": "product-medias",
              "settings": {
                "product": "{{ closest.product }}"
              }
            }
          },
          "block_order": [
            "text_1",
            "price_1",
            "product_medias_1"
          ]
        }
      },
      "block_order": ["group_1"]
    }
  },
  "order": ["custom_section_1"]
}

3. Ngirim Sumber Daya Lewat Liquid

Sumber keempat: kirim sumber daya langsung ke tag content_for pakai parameter closest.<tipe>:

  1. {% content_for "blocks", closest.product: <Product Drop> %}
  2. {% content_for "blocks", closest.collection: <collection Drop> %}
  3. {% content_for "blocks", closest.article: <ArticleDrop> %}
  4. {% content_for "blocks", closest.blog: <BlogDrop> %}
  5. {% content_for "blocks", closest.page: <PageDrop> %}
  6. {% content_for "blocks", closest.metaobject.<tipe_definisi>: <metaobjectDrop> %}

content_for "block" (static block) juga nerima sintaks yang sama. Kalau tipenya gak cocok sama daftar ini, error.

Kasus paling umum: loop produk di koleksi, di mana tiap kartu harus dapat produk yang lagi di-loop:

<ul class="product-grid">
  {% for product in block.settings.collection.products %}
    <li>
      {% content_for "block", type: "product-card", id: "card", closest.product: product %}
    </li>
  {% endfor %}
</ul>
{% schema %}
{
  "name": "Product grid",
  "settings": [{
    "type": "collection",
    "id": "collection",
    "label": "Collection"
  }],
  "presets": [{
    "name": "Product grid",
    "blocks": [
      {
        "id": "card",
        "type": "product-card",
        "static": true,
        "settings": {
          "product": "{{ closest.product }}"
        },
        "blocks": [
          {
            "type": "price",
            "settings": {
              "product": "{{ closest.product }}"
            }
          }
        ]
      }
    ]
  }]
}
{% endschema %}

Ini ngerangkai semuanya: static block product-card (karena dirender di loop, dan block dinamis gak bisa di loop) yang dapat closest.product: product dari iterasi, dan semua block anaknya (price, dan seterusnya) otomatis ngikutin lewat {{ closest.product }}. Satu block kartu produk, dipakai buat ratusan produk.

Urutan resolusi closest kalau ada sumber Liquid:

  1. Setter konteks Liquid terdekat (parameter content_for).
  2. Setting block leluhur terdekat.
  3. Setting sumber daya section.
  4. Sumber daya template.

4. Di Theme Editor

Merchant juga bisa nyambungin setting ke sumber daya terdekat lewat pemilih dynamic source di theme editor. Waktu ngedit block teks di template produk, mereka bisa pilih konteks: produk terdekat, produk yang diset di section, atau produk template. Setelah pilih konteks, mereka pilih field yang kompatibel sama tipe setting-nya.

Ringkasan

  1. Theme block = file di /blocks dengan markup, aset opsional, dan schema wajib, punya akses ke block, section, dan object global, tapi gak bisa nerima variabel.
  2. Preset wajib biar block muncul di pemilih block.
  3. Section opt-in lewat @theme di blocks dan {% content_for 'blocks' %}, dan gak bisa dicampur sama section block.
  4. Block bersarang pakai mekanisme yang sama (blocks di schema, content_for 'blocks' di markup), maksimal 8 tingkat, dan theme block gak bisa definisi block lokal.
  5. Preset bisa ngerakit block lain jadi layout siap pakai, termasuk bersarang.
  6. tag nerima string apapun sampai 50 karakter, tag: null ngilangin pembungkus tapi wajib satu elemen level atas dengan block.shopify_attributes.
  7. Static block dirender pakai content_for "block" dengan type dan id yang kamu tentuin, gak bisa dipindah atau dihapus merchant, bisa bersyarat dan di loop, bisa nerima data sembarang, gak dihitung max_blocks.
  8. ID block cukup unik di induk langsungnya, dan static block gak masuk block_order.
  9. Block dengan preset tersedia di semua section @theme, pakai awalan _ buat private block yang harus disebut eksplisit.
  10. closest.<tipe> ngambil sumber daya terdekat dari block sendiri → block induk → section → template, dan bisa di-override lewat parameter closest.<tipe>: di content_for.
  11. Pola kartu produk di loop: static block + closest.product: product, semua block anak otomatis ngikutin.

Bab selanjutnya kita bahas bahan baku semua schema di atas: setting. Semua tipe input dari text sampai product_list, atribut standarnya, nilai yang dikembalikan ke Liquid, dan setting sidebar buat ngerapiin editor.