Dokumentasi theme

Ringkasan

Theme Fauqa One Click memakai Liquid dan meniru Shopify Online Store 2.0: template JSON berisi daftar section, setiap section membawa {% schema %} sendiri, dan section group untuk header/footer. Developer theme Shopify bisa langsung bekerja; bedanya ada pada objek e-commerce yang tidak tersedia (lihat Porting dari Shopify).

Theme bisa diedit langsung di browser (Theme → Edit code), atau diunduh sebagai .zip, diubah di komputer, lalu diunggah lagi. Setiap simpan dan unggah divalidasi; file yang gagal validasi tidak pernah menggantikan file yang sedang tayang.

Struktur folder

layout/
  theme.liquid            wajib. Kerangka HTML
  password.liquid         opsional. Halaman password / segera hadir
templates/                JSON: daftar & urutan section per tipe halaman
  index.json              wajib
  page.json               wajib
  page.contact.json       template alternatif (suffix "contact")
  product.json  collection.json  list-collections.json
  blog.json  article.json  search.json  404.json  password.json
sections/
  header-group.json       section group
  footer-group.json
  hero.liquid             HTML Liquid + {% schema %}
snippets/                 {% render 'card-product', product: p %}
assets/                   css, js, svg, gambar, font → {{ 'base.css' | asset_url }}
config/
  settings_schema.json    wajib. Definisi theme settings
  settings_data.json      nilai theme settings + preset gaya
locales/
  id.default.json  en.json    string untuk filter t

Belum didukung: folder blocks/ (theme blocks) dan nested blocks. Block didefinisikan di schema section, seperti OS 2.0 awal.

Layout

layout/theme.liquid wajib memanggil {{ content_for_header }} di <head> (SEO, canonical, hreflang, data terstruktur, kode tambahan pemilik situs) dan {{ content_for_layout }} di tempat isi halaman. Badge {{ powered_by_link }} wajib tampil; bila theme tidak memanggilnya, badge disisipkan otomatis sebelum </body>.

<!doctype html>
<html lang="{{ request.locale.iso_code }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{{ page_title }}</title>
  <meta name="description" content="{{ page_description | escape }}">
  {{ 'base.css' | asset_url | stylesheet_tag }}
  {{ content_for_header }}
</head>
<body>
  {% sections 'header-group' %}
  <main id="main">{{ content_for_layout }}</main>
  {% sections 'footer-group' %}
  {{ powered_by_link }}
</body>
</html>

Template JSON

Template berisi section beserta nilai setting-nya. Urutan tampil mengikuti order; block mengikuti block_order. Section dengan "disabled": true tidak dirender. Template alternatif memakai suffix (page.contact.json) dan dipilih per halaman/produk di admin.

{
  "sections": {
    "hero": {
      "type": "hero",
      "settings": { "heading": "Solusi baja untuk industri", "height": "large" },
      "blocks": {
        "btn-1": { "type": "button", "settings": { "label": "Lihat produk", "link": "/collections/all" } }
      },
      "block_order": ["btn-1"]
    },
    "clients": { "type": "logo-list", "disabled": false, "settings": {} }
  },
  "order": ["hero", "clients"]
}

Maksimal 25 section per template dan 50 block per section.

Section & schema

Pasang {{ section.fauqa_attributes }} di elemen terluar section dan {{ block.fauqa_attributes }} di setiap block, agar klik di pratinjau editor memilih section/block yang tepat. Alias shopify_attributes juga tersedia.

<section class="hero hero--{{ section.settings.height }}" {{ section.fauqa_attributes }}>
  <h1>{{ section.settings.heading }}</h1>
  {% for block in section.blocks %}
    {% case block.type %}
      {% when 'button' %}
        <a href="{{ block.settings.link }}" class="btn" {{ block.fauqa_attributes }}>{{ block.settings.label }}</a>
    {% endcase %}
  {% endfor %}
</section>

{% schema %}
{
  "name": "Hero",
  "class": "section-hero",
  "settings": [
    { "type": "text", "id": "heading", "label": "Judul", "default": "Judul" },
    { "type": "select", "id": "height", "label": "Tinggi", "default": "large",
      "options": [{ "value": "small", "label": "Kecil" }, { "value": "large", "label": "Besar" }] }
  ],
  "blocks": [
    { "type": "button", "name": "Tombol", "limit": 2,
      "settings": [{ "type": "text", "id": "label", "label": "Teks" }, { "type": "url", "id": "link", "label": "Link" }] }
  ],
  "max_blocks": 4,
  "presets": [{ "name": "Hero", "blocks": [{ "type": "button" }] }],
  "enabled_on": { "templates": ["index", "page"] }
}
{% endschema %}
  • presets: section muncul di daftar “Tambah section” editor. Tanpa preset, section hanya bisa dipakai dari template JSON.
  • limit (per tipe block), max_blocks, enabled_on / disabled_on dihormati editor.
  • class ditambahkan ke pembungkus <div id="fauqa-section-<id>" class="fauqa-section">; tag mengganti elemen pembungkusnya.
  • Section statis: {% section 'header' %}, nilainya di settings_data.json → current.sections.header. Section group: {% sections 'header-group' %} membaca sections/header-group.json.

Tipe setting

TipeKeterangan
text, textareaTeks satu baris / beberapa baris
richtext, inline_richtextHTML terbatas dari editor teks; disanitasi
html, liquidHanya owner/admin. liquid dirender sebagai Liquid
number, rangerange wajib min, max, step
checkbox, select, radioselect/radio wajib options
color, color_background, color_schemeWarna, gradien, skema dari theme settings
image_picker, video, video_urlDari file manager; video_url YouTube/Vimeo
url, page, product, product_list, collection, collection_list, blog, article, link_listLink dan referensi konten
font_pickerGoogle Fonts terkurasi
header, paragraphPenanda di panel editor, tanpa nilai

Objek

ObjekIsi
sitename, url, logo, favicon, tagline, contact (email, phone, whatsapp, address), social, hours, locale
settingsTheme settings dari settings_data.json (preset aktif atau current)
requestpath, host, locale.iso_code, design_mode (true di editor), page
localizationavailable_languages[] (iso_code, name, url, root_url), language
routesroot_url, search_url, collections_url, all_products_collection_url
linklistslinklists['main-menu'].links[] → title, url, current, child_active, links
pages, collections, blogsBisa di-loop atau diakses per handle: collections['atap']
pagetitle, content, url, handle, template_suffix, seo
producttitle, summary, content, url, images, featured_image, specs[] (label, value), price_label, tags, downloads[], cta (type, label, url), related[]
collectiontitle, description, url, image, products[], products_count
blog / articleblog: title, url, articles[]; article: title, excerpt, content, image, author, tags, published_at, url
searchperformed, terms, results[] (object_type, title, url, excerpt, image), results_count
section / blockid, type, settings, blocks, index, fauqa_attributes
templatename, suffix
page_title, page_description, page_image, canonical_urlUntuk tag meta

Harga hanya tampilan (price_label, mis. “Mulai Rp 85.000”); tidak ada keranjang atau checkout.

Tag & filter

Tag: semua tag standar LiquidJS (if, for, case, assign, capture, render, raw, liquid, echo, …) ditambah section, sections, schema, form, paginate, style, stylesheet, javascript.

FilterContoh
asset_url{{ 'base.css' | asset_url | stylesheet_tag }}, {{ 'theme.js' | asset_url | script_tag }}
image_url, image_tag{{ product.featured_image | image_url: width: 800 | image_tag: loading: 'lazy' }} → WebP + srcset
file_url{{ 'hero.jpg' | file_url }}: file dari file manager situs
t{{ 'contact.send' | t }}: string dari locales/<bahasa>.json
date{{ article.published_at | date: '%d %B %Y' }}: nama bulan sesuai bahasa
money{{ product.price_label | money }}: label harga apa adanya
link_to, handleize{{ 'Tentang' | link_to: '/pages/tentang-kami' }}
default_pagination{{ paginate | default_pagination }}
placeholder_svg_tag{{ 'image' | placeholder_svg_tag: 'placeholder' }}
{% paginate collection.products by 12 %}
  {% for product in collection.products %}
    {% render 'card-product', product: product %}
  {% endfor %}
  {{ paginate | default_pagination }}
{% endpaginate %}

Form

{% form 'contact' %} membuat <form method="post" action="/contact"> lengkap dengan field tersembunyi, honeypot anti-spam, dan Cloudflare Turnstile bila aktif. Tipe: contact, inquiry (minta penawaran; berikan produk sebagai argumen), newsletter. Kiriman masuk ke inbox Form di admin dan email pemilik situs.

{% form 'inquiry', product %}
  {% if form.posted_successfully %}
    <p role="status">{{ 'contact.success' | t }}</p>
  {% else %}
    {% if form.errors.size > 0 %}<p role="alert">{{ form.errors | join: ' ' }}</p>{% endif %}
    <input type="text" name="contact[name]" required>
    <input type="email" name="contact[email]" required>
    <input type="tel" name="contact[phone]">
    <textarea name="contact[body]" required></textarea>
    <button type="submit">{{ 'contact.send' | t }}</button>
  {% endif %}
{% endform %}

Jangan membuat field password atau data kartu: validator memberi peringatan karena form seperti itu di situs company bisa dianggap phishing.

Bahasa

Situs bisa punya dua bahasa (Indonesia dan English). Bahasa kedua tampil di /en/… (atau /id/…). String theme ada di locales/id.default.json dan locales/en.json, dipanggil dengan filter t; kunci yang tidak ada di bahasa aktif diambil dari bahasa utama situs. Konten dan teks section diterjemahkan pemilik situs di menu Terjemahan, jadi theme tidak perlu menangani apa pun: section.settings sudah berisi teks bahasa aktif. Link internal di menu otomatis diberi awalan bahasa; untuk link lain pakai routes.root_url.

{% for language in localization.available_languages %}
  <a href="{{ language.url }}" {% if language.iso_code == request.locale.iso_code %}aria-current="true"{% endif %}>
    {{ language.iso_code | upcase }}
  </a>
{% endfor %}

Theme editor

Di editor, situs dirender dengan request.design_mode = true dan perubahan setting dirender ulang per section (Section Rendering API). JavaScript section yang memasang event listener atau slider harus mendengarkan event berikut agar tetap bekerja setelah dirender ulang:

EventKapan
fauqa:section:loadSection baru dirender ulang / ditambahkan
fauqa:section:unloadSection akan diganti / dihapus
fauqa:section:select, fauqa:section:deselectSection dipilih di panel editor
fauqa:block:select, fauqa:block:deselectBlock dipilih (mis. buka slide yang sesuai)
document.addEventListener('fauqa:section:load', (e) => initSlider(e.target));
document.addEventListener('fauqa:block:select', (e) => goToSlide(e.target));

event.detail berisi sectionId dan, untuk block, blockId. Kode tambahan <head> pemilik situs tidak dijalankan di editor.

Validasi & batas

  • ZIP maksimal 50 MB dan 1.000 file; hanya folder di atas. Folder pembungkus (mis. my-theme/) dibuang otomatis.
  • Wajib ada layout/theme.liquid, templates/index.json, templates/page.json, config/settings_schema.json.
  • Setiap .liquid di-parse, setiap JSON dan {% schema %} dicek; laporan error menyebut file dan baris. Section yang dipakai template harus ada.
  • Nama file: huruf kecil, angka, _, -. Ekstensi aset: css, js, json, svg, png, jpg, webp, gif, ico, woff, woff2, ttf, otf (maks. 5 MB per aset).
  • Render dibatasi ±500 ms per template dan tanpa akses jaringan atau file: template hanya membaca objek di atas. Section yang error tidak menjatuhkan halaman (di editor, pesan error tampil di tempatnya).
  • JavaScript theme berjalan di domain situs, terpisah dari admin.

Porting dari Shopify

Struktur folder, template JSON, schema, section group, render, t, asset_url, dan form sama. Yang perlu diubah:

  • Hapus cart, customer, checkout, variant, dan form product/cart. Ganti tombol beli dengan product.cta (WhatsApp, form penawaran, atau link).
  • product.price bukan angka; pakai product.price_label.
  • shop menjadi site; shop.name → site.name.
  • Theme blocks (blocks/) dan app blocks belum didukung.

Cara tercepat memulai: buka Theme → Edit code → Unduh .zip dari salah satu theme bawaan, lalu ubah dari sana.