Pengembangan tema

Dari theme.json sampai brand yang tayang: isi sebuah tema dan cara memasukkannya ke AtlasCMS.

Baca 6 menit

Apa itu paket tema

Tema mengubah block milik brand menjadi situs web. Tema adalah paket berversi dengan manifest theme.json, template dan part bawaan yang ditulis sebagai pohon block, definisi block untuk block tambahan dari tema, dan beberapa gambar. API menyimpan snapshot manifest dan data per brand (tema mana yang aktif, opsinya, override template). API tidak pernah menyimpan atau menjalankan kode tema.

Paket yang Anda unggah hanya berisi data. API membaca zip, memeriksa setiap entri, lalu menyimpan JSON-nya. Kode komponen tidak dijalankan dan tidak disajikan. Komponen yang menggambar block Anda ada di situs yang merender brand, dibangun di atas paket layer yang dijelaskan di @atlas/nuxt.

Susunan paket yang umum:

package layouttext
theme.json
blocks/definitions.json
templates/index.json
templates/page.json
parts/header.json
parts/footer.json
screenshot.png

Manifest theme.json

Manifest berada di root paket. Setiap key di bawah diperiksa saat unggah dan oleh php artisan themes:sync.

theme.jsonjson
{
  "manifestVersion": 1,
  "slug": "acme",
  "name": "Acme",
  "version": "1.0.0",
  "requires": { "api": ">=0.1.0" },
  "blocks": { "prefix": "acme-" },
  "templates": [
    { "slug": "index", "title": "Fallback" },
    { "slug": "page", "title": "Page" }
  ],
  "customTemplates": [
    { "slug": "landing-no-header", "title": "Landing", "types": ["page"] }
  ],
  "parts": [
    { "slug": "header", "area": "header", "title": "Header" },
    { "slug": "footer", "area": "footer", "title": "Footer" }
  ],
  "menuLocations": [
    { "key": "header", "title": "Main navigation", "maxDepth": 3 }
  ],
  "styleVariations": [],
  "tokens": {},
  "options": {
    "type": "object",
    "properties": {
      "headerCtaLabel": { "type": "string", "maxLength": 40, "x-translatable": true }
    }
  }
}
KeyAturan
manifestVersionHarus 1.
slug, versionSlug huruf kecil paling banyak 64 karakter, dan versi SemVer seperti 1.2.0.
blocks.prefixWajib. Tipe block Anda harus diawali prefix ini. atlas- dicadangkan.
templatesTemplate yang dibawa paket. index wajib ada, ia adalah fallback terakhir.
customTemplatesTemplate yang bisa dipilih editor untuk sebuah entri. Masing-masing menyebut types entri yang cocok. Slug-nya tidak boleh sama dengan nama yang sudah dimiliki hierarki template.
partsPohon block yang bisa dipakai ulang, masing-masing dengan area seperti header atau footer.
menuLocationsKey menu yang dirender tema. maxDepth adalah bilangan bulat 1 sampai 3.
styleVariations, tokensSet token. Nilainya tidak boleh menunjuk ke file remote (//, ://, url(, image-set().
requires.apiDaftar pembanding seperti >=0.3.0. Paket yang butuh API lebih baru ditolak.
optionsPengaturan yang boleh diubah brand, dideklarasikan sebagai JSON schema.

Manifest tidak boleh mendeklarasikan scripts, head, routes, atau server. Paket yang diunggah oleh brand tidak boleh memakai extends.

Block dan definisi block

Definisi block menyatakan prop apa yang diterima sebuah block. Ia menggerakkan formulir editor dan validasi server untuk setiap halaman yang memakai block itu. Definisi berbentuk { "type", "version", "schema" }, dan tipenya harus diawali blocks.prefix Anda.

blocks/definitions.jsonjson
[
  {
    "type": "acme-hero",
    "version": 1,
    "schema": {
      "type": "object",
      "required": ["heading"],
      "properties": {
        "heading": { "type": "string", "maxLength": 120 },
        "image": { "type": "object" }
      }
    }
  }
]

Definisi bisa dimuat dengan tiga cara:

  • Taruh di blocks/definitions.json di dalam paket. Unggah dan themes:sync membacanya.
  • Jalankan php artisan blocks:sync definitions.json --brand=acme di server. Tanpa --brand, definisi disimpan sebagai definisi global.
  • Sebagai admin, panggil PUT /v1/manage/block-definitions dengan { "definitions": [ ... ] } (1 sampai 200 item). Definisi yang disimpan lewat cara ini milik brand.
PUT/v1/manage/block-definitions

Block bersarang paling dalam tiga tingkat. Dua nama atlas-template-part dan atlas-post-content adalah batas renderer: keduanya tidak butuh definisi dan tidak ada jalur tulis yang menerima definisi untuk keduanya. Selama brand belum punya definisi apa pun, validasi block dilewati.

Template dan part

Template adalah pohon block yang dipilih oleh hierarki template. Untuk sebuah path, API menyusun daftar kandidat dan kandidat pertama yang ada akan dipakai. Halaman di /tentang mencoba page-tentang, page, singular, index. Artikel mencoba single-{type}-{slug}, single-{type}, single, singular, index. Root locale mencoba front-page lebih dulu, halaman artikel mencoba home, archive-post, archive, dan jika tidak ada yang cocok dipakai 404.

Untuk setiap kandidat, API memeriksa berurutan:

  1. Override terbit milik brand ini untuk locale yang diminta.
  2. Override terbit untuk locale default, selama setting locale_fallback tidak false.
  3. File yang dibawa paket.

Ketika file paket yang menjawab, payload halaman berisi "source": "package" dengan "blocks": null, dan renderer memakai salinannya sendiri. Part tanpa override membawa block bawaan dari paket.

Editor bisa mengubah template atau part tanpa menyentuh paket. Panggilan ini butuh publisher:

PanggilanEfek
PUT /v1/manage/theme/templates/{kind}/{slug}/draftMenyimpan { locale?, blocks } sebagai draf. kind adalah template atau part.
POST /v1/manage/theme/templates/{kind}/{slug}/publishMembuat draf tayang. 422 jika tidak ada draf.
DELETE /v1/manage/theme/templates/{kind}/{slug}Membuang override sehingga bawaan paket kembali dipakai.

Draf bukan output yang tayang. Menerbitkannya mencatat audit, menaikkan versi konten brand, dan mengantrekan webhook purge. atlas-post-content merender isi entri, jadi hanya boleh ada di template yang merender satu entri, dan satu kali per pohon. Part tidak pernah memuatnya.

Opsi tema dan registry setting

AtlasCMS menyimpan setting dalam registry: setiap setting inti dideklarasikan sekali dengan tipe, nilai bawaan, dan peran yang boleh menulisnya. GET /v1/manage/settings/definitions menampilkannya untuk semua anggota. Opsi tema adalah himpunan terpisah. Objek options di manifest Anda satu-satunya penentu key opsi yang ada, dan PUT /v1/manage/settings menolaknya.

Opsi memakai subset JSON schema yang sama dengan prop block, ditambah dua penanda:

KeyArti
x-translatableNilainya adalah map dengan key locale brand. Situs menerima locale yang diminta, lalu locale default.
x-privateOpsi tidak pernah sampai ke situs. Hanya anggota yang melihatnya di dashboard.
formatSalah satu dari uri (diperiksa sebagai tautan aman), media (file siap milik brand), color (#rrggbb), atau html (dibersihkan saat simpan).

Opsi format: media disimpan sebagai id media dan dikirim sebagai { media_id, media: { url, mime, width, height, alt, focal } }. Satu brand boleh punya paling banyak 100 opsi, dan satu nilai paling besar 8 KB. Nilai kosong mengembalikan opsi ke nilai bawaannya.

Opsi punya salinan draf dan salinan tayang, sehingga editor bisa melihat pratinjau sebelum menerbitkan:

PanggilanPeran
GET /v1/manage/theme/options/{slug}Semua anggota
PUT /v1/manage/theme/options/{slug}/draft dengan { "options": { ... } }Publisher
POST /v1/manage/theme/options/{slug}/publishPublisher
DELETE /v1/manage/theme/options/{slug}/draftPublisher

GET /v1/public/theme yang publik mengembalikan opsi tayang dari tema aktif. Permintaan dengan token preview menerima draf, dan jawaban preview tidak pernah di-cache.

Sinkronkan tema di server

Operator dengan akses shell bisa menyimpan direktori paket atau manifest saja sebagai tema platform yang dilihat semua brand:

terminalbash
php artisan themes:sync themes/acme
php artisan themes:sync themes/acme/theme.json --definitions=build/definitions.json

Perintah ini memvalidasi manifest dan satu file untuk setiap template dan part. Satu file yang salah menolak seluruh sinkronisasi dan tidak menulis apa pun. Perintah ini juga menyinkronkan definisi block. Ia menyimpan snapshot dan tidak pernah mengaktifkan tema.

Unggah tema

Admin brand bisa mengunggah paket sebagai zip. Tema itu kemudian hanya milik brand tersebut.

POST/v1/manage/themes

Body-nya multipart/form-data dengan file di package dan boolean opsional dry_run. Selalu jalankan dry run lebih dulu: ia menjalankan pemeriksaan yang sama dan tidak menulis apa pun.

terminalbash
curl -s -X POST https://api.atlascms.id/v1/manage/themes \
  -b cookies.txt -H "X-CSRF-TOKEN: $CSRF" -H "X-Brand-Id: $BRAND_ID" \
  -F "[email protected]" -F "dry_run=1"
responsejson
{
  "dry_run": true,
  "result": "would_create",
  "theme": { "slug": "acme", "name": "Acme", "version": "1.0.0" },
  "counts": { "templates": 2, "parts": 2, "blocks": 1, "files": 8 },
  "errors": [],
  "warnings": []
}

result bernilai would_create pada dry run, lalu created atau unchanged pada unggahan sungguhan. unchanged berarti slug dan versi yang sama dengan isi yang sama sudah tersimpan.

Aturan paket:

  • theme.json berada di root zip. Satu folder pembungkus tidak diterima.
  • Hanya file .json, .png, .jpg, .jpeg, dan .webp. Tanpa file tersembunyi, symlink, atau arsip terenkripsi. Gambar harus benar-benar gambar.
  • Paling besar 5 MB terkompresi, 200 file, 2 MB per file, dan 20 MB setelah diekstrak. Satu brand menyimpan sampai 10 tema dan 20 versi per tema.
  • Slug tidak boleh milik tema platform, dan blocks.prefix tidak boleh bentrok dengan block global.
  • Versi bersifat tetap. Slug dan versi yang sama dengan isi berbeda dijawab 409 version_exists: naikkan version di manifest.

Paket yang punya galat apa pun dijawab 422 dengan bentuk yang sama dan errors terisi, setiap item berbentuk { file, path, code, message }. Kode di antaranya manifest_missing, file_not_allowed, quota_exceeded, prefix_mismatch, dan remote_reference. Screenshot yang hilang hanya peringatan.

Unggahan menaikkan versi konten dan mencatat audit theme.package.uploaded. Unggahan tidak mengalihkan brand ke tema itu.

Unggah dari CI dengan token developer

Admin bisa membuat token developer untuk CLI atlas atau job CI. Token ini membawa satu scope, theme:write, dan hanya menjangkau dua route tema di bawah. Tidak butuh sesi dan tidak butuh X-Brand-Id, karena token menyebut brand-nya.

terminalbash
curl -s -X POST https://api.atlascms.id/v1/developer/themes \
  -H "Authorization: Bearer $ATLAS_DEV_TOKEN" \
  -F "[email protected]" -F "dry_run=1"
POST/v1/developer/themes

Jawabannya berbentuk sama dengan unggahan dari dashboard, dibatasi 10 per menit per token. GET /v1/developer/themes menampilkan daftar tema brand. Lihat Token dan keamanan untuk cara token dibatasi scope dan dicabut.

Ganti tema aktif

Mengganti tema adalah tindakan admin, dalam dua langkah.

POST/v1/manage/theme/active/preflight

Kirim { "theme": "acme" }. Pemeriksaan ini tidak menulis apa pun dan menjawab ready, ditambah apa yang akan hilang dari brand: key menu yang tidak punya lokasi di tema, entri yang custom template-nya tidak dideklarasikan tema, dan peringatan soal kedalaman menu, style variation, serta opsi tersimpan yang akan ditolak skema baru. Override tidak pernah menghalangi pergantian: ia tetap terikat pada tema yang membuatnya dan kembali saat Anda berganti balik.

PUT/v1/manage/theme/active

Kirim { "theme": "acme" }, atau { "theme": null } untuk tanpa tema. API menyematkan versi yang sudah disinkronkan, mengosongkan style variation saat slug berubah, mencatat audit theme.activated, dan mengantrekan webhook purge dengan paths: ["*"]. Tema yang diunggah satu brand hanya bisa diaktifkan oleh brand itu.

Pratinjau tema sebelum tayang

PUT/v1/manage/theme/active/draft

Kirim { "theme": "acme" } (admin) untuk menyetel draf pratinjau, atau { "theme": null } untuk mengosongkannya. Hanya permintaan dengan token preview yang merender tema itu, jadi pengunjung tetap melihat tema yang tayang. Draf pratinjau tidak menulis purge dan tidak menggeser versi konten.

Urutan kerja

Unggah dengan dry_run sampai bersih, unggah sungguhan, setel draf pratinjau dan telusuri situs dengan token preview, lalu jalankan preflight dan aktifkan.

Terbitkan untuk konten

Paket tema diunggah, tidak pernah diterbitkan. Terbitkan dipakai untuk entri, draf template dan part, serta draf opsi tema.

Apakah halaman ini membantu?

Usulkan perubahan