Di 21 Gambaran Arsitektur Theme kita lihat enam lapisan theme. Sekarang kita mulai dari yang paling luar: layout, kerangka HTML yang ngebungkus semua halaman.

Layout itu dasar theme, tempat semua template dirender. Bayangin layout sebagai bingkai foto: bingkainya sama terus, yang ganti-ganti cuma fotonya (template). Header, footer, <head> dengan meta tag dan CSS, itu semua bingkainya.

Layout itu file Liquid yang bikin kamu bisa naruh konten yang diulang di banyak jenis halaman dalam satu tempat. Kalau gak ada layout, tiap template harus nulis ulang header dan footer sendiri-sendiri, dan tiap ganti logo harus edit 15 file.

Lokasi

Di folder layout/:

└── theme
  ├── layout
  |   ├── theme.liquid
  |   ...
  ├── templates
  ...

Dua Jenis Layout

  1. General, buat semua halaman non-checkout. File bawaannya theme.liquid, yang wajib ada di semua theme. Ini yang kita bahas di bab ini.
  2. Checkout, buat halaman checkout, cuma buat merchant Shopify Plus lewat checkout.liquid. Tapi ini udah dihentikan: gak didukung buat langkah Information, Shipping, dan Payment, dan dihentikan buat halaman Thank you dan Order status sejak 28 Agustus 2025 (toko non-Plus sampai 26 Agustus 2026). Toko yang masih pakai harus pindah ke Checkout Extensions. Bahasannya di 34 checkout.liquid (deprecated).

Struktur Dasar

Karena layout itu dasar theme, isinya harus ngikutin struktur dokumen HTML standar, dan hampir selalu berisi dua object Liquid:

<!DOCTYPE html>
<html>
  <head>
    ...
    {{ content_for_header }}
    ...
  </head>
  <body>
    ...
    {{ content_for_layout }}
    ...
  </body>
 </html>

Dua object ini wajib ada di theme.liquid. Kalau salah satunya gak ada, kamu gak bisa nyimpen atau nge-update file-nya, baik lewat code editor maupun Shopify CLI. Jadi ini bukan saran, ini syarat.

1. content_for_header

Wajib di dalam <head>. Object ini ngeluarin semua skrip yang dibutuhin Shopify secara dinamis: hCaptcha, skrip app, analitik, skrip theme editor, dan lainnya.

Aturannya, udah dibahas di 13 Objects Global > 1. content_for_header: jangan pernah dimodifikasi atau di-parse. Isinya bisa berubah kapan aja, dan kalau kamu ngandelin isinya, kodemu bakal rusak tanpa peringatan.

2. content_for_layout

Wajib di antara <body> dan </body>. Object ini ngeluarin isi template yang lagi dirender. Ini titik di mana halaman produk, halaman koleksi, atau halaman apapun “disuntikkan” ke dalam bingkai.

❌ salah, content_for_layout di luar body, dan content_for_header hilang

<!DOCTYPE html>
<html>
  <head>
    <title>{{ page_title }}</title>
  </head>
  <body>
    {% sections 'header-group' %}
  </body>
</html>
{{ content_for_layout }}

✅ benar

<!DOCTYPE html>
<html>
  <head>
    <title>{{ page_title }}</title>
    {{ content_for_header }}
  </head>
  <body>
    {% sections 'header-group' %}
    {{ content_for_layout }}
    {% sections 'footer-group' %}
  </body>
</html>

Isi Layout

Layout itu file .liquid, jadi isinya HTML dan Liquid biasa. Dia bisa akses semua object global dari 13 Objects Global, plus dua object di atas. Yang biasanya ditaruh di layout:

  1. Meta tag dan SEO di <head>: <title>, meta description, Open Graph, canonical. Bahasannya di 48 SEO Metadata, hreflang, robots.txt.
  2. CSS dan font yang dipakai semua halaman.
  3. Section group header dan footer lewat tag sections.
  4. Skrip global yang dibutuhin di semua halaman.

Ini contoh theme.liquid yang realistis, ngerangkai hal-hal yang udah kita pelajari:

<!doctype html>
<html lang="{{ request.locale.iso_code }}" dir="{{ request.locale.direction }}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="canonical" href="{{ canonical_url }}">
 
    {%- if settings.favicon != blank -%}
      <link rel="icon" type="image/png" href="{{ settings.favicon | image_url: width: 32, height: 32 }}">
    {%- endif -%}
 
    <title>
      {{ page_title }}
      {%- if current_tags %} &ndash; tagged "{{ current_tags | join: ', ' }}"{% endif -%}
      {%- if current_page != 1 %} &ndash; Page {{ current_page }}{% endif -%}
      {%- unless page_title contains shop.name %} &ndash; {{ shop.name }}{% endunless -%}
    </title>
 
    {% if page_description %}
      <meta name="description" content="{{ page_description | escape }}">
    {% endif %}
 
    {% render 'meta-tags' %}
 
    {% style %}
      {{ settings.type_body_font | font_face: font_display: 'swap' }}
      {{ settings.type_header_font | font_face: font_display: 'swap' }}
 
      :root {
        --font-body-family: {{ settings.type_body_font.family }}, {{ settings.type_body_font.fallback_families }};
        --font-heading-family: {{ settings.type_header_font.family }}, {{ settings.type_header_font.fallback_families }};
        --color-background: {{ settings.colors_background }};
        --color-text: {{ settings.colors_text }};
      }
    {% endstyle %}
 
    {{ 'base.css' | asset_url | stylesheet_tag }}
 
    {{ content_for_header }}
  </head>
 
  <body class="template-{{ template.name }}{% if template.suffix %} template-{{ template.name }}-{{ template.suffix }}{% endif %}">
    <a class="skip-to-content-link" href="#MainContent">
      {{ 'accessibility.skip_to_text' | t }}
    </a>
 
    {% sections 'header-group' %}
 
    <main id="MainContent" role="main">
      {{ content_for_layout }}
    </main>
 
    {% sections 'footer-group' %}
 
    <script src="{{ 'global.js' | asset_url }}" defer="defer"></script>
  </body>
</html>

Bedah bagian-bagian pentingnya:

  1. lang dan dir dari request.locale, biar bahasa kanan-ke-kiri kaya Arab tampil benar. Dari 13 Objects Global > 3. shop_locale.
  2. canonical_url buat SEO.
  3. <title> yang dirakit dari page_title, current_tags, current_page, dan shop.name, semuanya object global.
  4. font_face dengan font_display: 'swap' dan CSS variable buat font dan warna, sesuai pola dari 06 Theme Editor dan Code Editor > 1. Pengaturan Warna biar live preview jalan.
  5. stylesheet_tag buat CSS utama.
  6. Class <body> dari template.name dan template.suffix, dibahas di bawah.
  7. Skip link buat aksesibilitas, teksnya lewat t. Bahasannya di 55 Accessibility.
  8. sections 'header-group' dan sections 'footer-group', section group yang bisa diatur merchant.
  9. <main> dengan id="MainContent" yang ngebungkus content_for_layout.
  10. Skrip dengan defer biar gak ngeblok render.

CSS Selector per Template

Trik yang dipakai hampir semua theme: keluarin data dari object template sebagai class di <body>, biar kamu bisa bikin aturan CSS yang cuma berlaku di jenis halaman tertentu:

<body class="template-{{ template.name }}">
  ...
</body>

Terus di CSS:

.template-product {
  margin-bottom: 2em;
}

Halaman produk dapat template-product, halaman koleksi dapat template-collection, dan seterusnya. Nilai-nilai template.name ada di 13 Objects Global > template. Dengan nambahin template.suffix kaya di contoh di atas, alternate template product.pre-order.json dapat class tambahan template-product-pre-order.

Layout Alternatif

Kamu bisa bikin lebih dari satu layout. Misalnya layout/full-width.liquid tanpa header dan footer buat landing page kampanye, atau layout/minimal.liquid buat halaman gift card yang mau dicetak.

Cara nentuin layout mana yang dipakai itu di level template, dan caranya beda tergantung jenis template:

  1. Template JSON: pakai atribut layout di file JSON-nya. Bahasannya di 23 Templates.
  2. Template Liquid: pakai tag layout dari 12 Tags Khusus Theme > layout.

Template JSON:

{
  "layout": "full-width",
  "sections": { ... },
  "order": [ ... ]
}

Template Liquid:

{% layout 'full-width' %}

Dan dua-duanya bisa gak pakai layout sama sekali: "layout": false di JSON, atau {% layout none %} di Liquid. Hasilnya cuma isi template-nya doang, tanpa <html>, <head>, apapun. Ini yang dipakai template gift_card.liquid yang punya struktur HTML sendiri.

Kalau atribut atau tag-nya gak disebut, theme.liquid yang dipakai.

❌ salah, layout alternatif tapi lupa content_for_layout, template-nya gak pernah muncul

{% comment %} layout/full-width.liquid {% endcomment %}
<!doctype html>
<html>
  <head>{{ content_for_header }}</head>
  <body>
    <h1>Kampanye Besar</h1>
  </body>
</html>

✅ benar, layout alternatif tetap butuh dua object wajib

<!doctype html>
<html>
  <head>{{ content_for_header }}</head>
  <body>
    {{ content_for_layout }}
  </body>
</html>

Catatan: cuma theme.liquid yang diblokir nyimpen kalau dua object-nya hilang. Layout alternatif bisa disimpan tanpa itu, tapi ya hasilnya halaman kosong atau fitur Shopify yang gak jalan. Jadi tetap taruh.

Ringkasan

  1. Layout itu bingkai yang ngebungkus semua template, tempat konten yang diulang di banyak halaman: <head>, header, footer.
  2. theme.liquid wajib ada, dan wajib berisi content_for_header di <head> dan content_for_layout di <body>. Tanpa itu, file-nya gak bisa disimpan.
  3. content_for_header jangan dimodifikasi, isinya skrip Shopify yang bisa berubah kapan aja.
  4. content_for_layout itu titik suntik template ke dalam layout.
  5. Layout bisa akses semua object global, dan biasanya berisi meta tag, font, CSS, section group header/footer, dan skrip global.
  6. Class <body> dari template.name (dan template.suffix) buat CSS per jenis halaman.
  7. Layout alternatif dipilih di level template: atribut layout di JSON, tag layout di Liquid, atau false/none buat tanpa layout.
  8. checkout.liquid udah dihentikan, checkout dikustomisasi lewat Checkout Extensions.

Bab selanjutnya kita masuk ke lapisan berikutnya: template. Bedanya template JSON dan Liquid, struktur file JSON-nya, dan cara bikin beberapa template buat jenis halaman yang sama.