Sviluppatori · Formato del tema

Il formato del tema

Un tema è JSON e CSS. Nessun passaggio di build, nessun framework, nessun server da mandare avanti. La stessa funzione che decide se il suo tema si installa dalla nostra parte gira nella CLI e nell'editor, quindi un controllo pulito lì è un caricamento pulito. Per ogni nodo, componente e fonte dati, veda il riferimento temi.

Due vincoli

Li sappia prima di cominciare

Sono entrambi il motivo per cui il tema di qualcuno che non abbiamo mai incontrato può essere installato su un negozio dal vivo.

  • Un tema non porta JavaScript. Nessuno, in nessuna forma. Una sezione sono dati ed è la nostra vetrina a disegnarla, quindi non c'è niente da isolare. Tutto ciò che è interattivo è un componente che lei colloca per nome, e parecchi prendono la disposizione dal suo tema, quindi una fisarmonica nel suo tema ha l'aspetto della sua fisarmonica. Se le serve un comportamento che non è in elenco, ce lo dica: quella è una lacuna dalla nostra parte, ed è così che l'elenco cresce.
  • Lo stile è CSS semplice sui nostri token, non Tailwind. Scriva var(--shop-accent), var(--shop-font-heading), var(--shop-radius). Il suo theme.json imposta i valori predefiniti, e il commerciante può cambiarne qualunque senza toccare il suo CSS.

Struttura

La cartella

È questo che usano lo spazio di lavoro, la CLI e un caricamento zip. Tenere tutto nel solo theme.json funziona lo stesso; le cartelle sono per sua comodità, non un secondo formato.

harbour/
  theme.json            identity, tokens, theme settings, plugins
  theme.css             styling for the whole theme
  sections/<name>.json  one file per section: its form, its data, its markup, its CSS
  templates/<page>.json one file per page: which sections, in which order
  AGENTS.md             the performance rules, for coding assistants
  README.md             yours

Nessun altro file viene accettato: niente immagini, font o script nella cartella. Un tema porta al massimo 60 sezioni e 2 MB in tutto.

Identità

theme.json

La testa del tema. La riga $schema le dà completamento e aiuto in linea in VS Code e nella maggior parte degli editor, da uno schema generato dal validatore stesso.

{
  "$schema": "https://whizzycommerce.com/schema/theme-v1.json",
  "dsl": 1,
  "slug": "harbour",
  "name": "Harbour",
  "version": "1.0.0",
  "description": "Big photography and quiet type for homeware shops.",
  "author": { "name": "Tide Studio", "url": "https://tide.example", "email": "help@tide.example" },
  "docsUrl": "https://tide.example/harbour",
  "specs": { "responsive": true, "rtl": false },
  "plugins": { "blog": "^2.0.0" },
  "tokens": { "colorAccent": "#1f3a5f", "radius": "0" },
  "settings": [],
  "migrations": {}
}
CampoCos'è
slugLettere minuscole, cifre e trattini. È permanente, e fa da prefisso ai tipi di sezione del suo tema.
versionSemver. Veda Versioni e revisione per cosa può cambiare ogni tipo di versione.
pluginsI plugin per cui il tema dispone le pagine, con un intervallo di versioni. Veda Plugin più sotto.
tokensI suoi valori predefiniti per i design token.
settingsScelte valide per tutto il tema che il commerciante fa una volta per negozio.
migrationsRinomine di sezioni, impostazioni e token, per i negozi che arrivano da una versione precedente.

Design

Token e impostazioni

I token sono i colori, i caratteri e le forme del negozio. Le impostazioni sono scelte sulla disposizione. Entrambi hanno i suoi valori predefiniti, e il commerciante può cambiarli tutti e due nella schermata Design del negozio.

TokenVariabile CSSPredefinito
colorBgvar(--shop-bg)#ffffff
colorFgvar(--shop-fg)#0f1115
colorAccentvar(--shop-accent)#0b0f19
colorMutedvar(--shop-muted)#6b7280
fontHeadingvar(--shop-font-heading)"Inter", system-ui, sans-serif
fontBodyvar(--shop-font-body)"Inter", system-ui, sans-serif
fontSizeBodyvar(--shop-font-size-body)16px
fontSizeHeadingvar(--shop-font-size-heading)60px

Questi sono i primi 8 di 28. Il riferimento li elenca tutti.

"settings": [
  { "key": "homeLayout", "label": "Home layout", "type": "select", "default": "roomy",
    "options": [{ "value": "roomy", "label": "Roomy" }, { "value": "compact", "label": "Compact" }] },
  { "key": "showNote", "label": "Show the delivery note", "type": "boolean", "default": true }
]

Una sezione legge un'impostazione del tema come { "get": "theme.homeLayout" } e le proprie come { "get": "settings.heading" }. Usi un'impostazione del tema quando la risposta è una per negozio, così il commerciante la cambia una volta invece che in ogni sezione.

Mattoni

Sezioni

Una sezione è quello che un commerciante aggiunge a una pagina. Dichiara un modulo, i dati che le servono, il suo CSS e il suo markup come un albero di nodi di render. Il modulo non lo costruisce mai lei: dichiarare campi e blocchi è quello che ne dà uno al commerciante.

{
  "type": "harbour.ticker",
  "label": "Ticker",
  "category": "layout",
  "description": "Short phrases across the page, in the accent colour.",

  "fields": [
    { "key": "speed", "label": "Speed", "type": "select", "default": "slow",
      "options": [{ "value": "slow", "label": "Slow" }, { "value": "fast", "label": "Fast" }] }
  ],
  "blocks": [{
    "type": "phrase", "label": "Phrase", "max": 6,
    "fields": [
      { "key": "text", "label": "Text", "type": "text", "default": "Free delivery" }
    ]
  }],

  "css": ".ticker-band { display: flex; gap: 3rem; background: var(--shop-accent) }",

  "render": [
    { "node": "box", "as": "section", "cls": "ticker-band", "children": [
      { "node": "slot", "children": [
        { "node": "text", "as": "span", "value": { "get": "block.text" } }
      ]}
    ]}
  ]
}
  • type è sempre <your slug>.<name>. Il nome del file è la parte dopo il punto.
  • blocks dà al commerciante un pulsante “Aggiungi frase”, limitato da max. slot disegna i suoi figli una volta per blocco, ed è questo che fa sì che block.text significhi questa frase.
  • render è un elenco di nodi, di questi tipi: box, text, rich, img, link, each, if, slot, icon, money, component. I valori sono espressioni come { "get": "product.title" } o { "lit": "Sale" }.

Fonti dati

Una sezione dichiara cosa le serve, e la pagina lo recupera prima di disegnare qualsiasi cosa. Due sezioni che chiedono lo stesso elenco costano una query. Un tema non può scrivere una query propria.

"data": [
  { "as": "picks", "source": "collection-products",
    "collection": { "get": "settings.collection" }, "limit": 8 }
],
"render": [
  { "node": "box", "cls": "picks-grid", "children": [
    { "node": "each", "in": { "get": "data.picks" }, "as": "item", "limit": 8,
      "children": [
        { "node": "component", "use": "product-card", "props": { "product": { "get": "item" } } }
      ],
      "empty": [
        { "node": "text", "as": "p", "value": { "lit": "Nothing to show here yet." } }
      ] }
  ]}
]

Componenti

I componenti sono le parti interattive e che conoscono il negozio: product-card, shop-logo, shop-menu, cart-link, search-box e altri. Lei li colloca e ci dà stile attorno, con props dove un componente ne accetta. Non può scriverne uno.

Il carrello, la pagina prodotto, la ricerca, l'accesso e le pagine di un plugin arrivano come dati in ambito più piccole parti che fanno una cosa ciascuna, come sheet, cart-remove, product-form, product-gallery, search-form e login-form. Le versioni già pronte sono costruite con le stesse parti, quindi un tema può disporne una qualsiasi in modo diverso: un carrello come popup invece che come cassetto, una scheda d'acquisto con un ordine suo. Il riferimento elenca ogni ambito e ogni parte.

Pagine

Template

Un template è la disposizione iniziale di una pagina: un elenco di sezioni collocate con le loro impostazioni. I commercianti la riordinano dopo.

[
  { "id": "hero", "type": "hero", "settings": { "heading": "Made to last" } },
  { "id": "picks", "type": "harbour.picks", "settings": { "heading": "New in", "limit": 4 } }
]
IdentificativoPagina
headerHeader
homeHome
collectionCategory page
productProduct page
cartCart page
searchSearch results
loginSign in page
registerCreate account page
footerFooter
blogL'elenco degli articoli del blog. Richiede il plugin blog dichiarato.
blog-postUn articolo del blog. Richiede il plugin blog dichiarato.

Un template con qualsiasi altro nome (header, home, collection, product, cart, search, login, register, footer, o le pagine di un plugin dichiarato) viene segnalato quando convalida, invece di installarsi in silenzio e non disegnare niente. Una pagina porta al massimo 40 sezioni.

Dipendenze

Plugin

Alcune pagine appartengono a un plugin, come il blog. Per disporre quelle pagine, dichiari il plugin in theme.json con l'intervallo di versioni contro cui ha costruito.

"plugins": { "blog": "^2.0.0" }
  • I suoi template possono poi usare le pagine e i tipi di sezione di quel plugin, come blog.index e blog.post, e i suoi componenti, come blog-post-list.
  • Installare il suo tema installa prima il plugin, così le pagine che ha disposto esistono.
  • Gli intervalli hanno le forme ^2.0.0, ~2.1.0, >=2.0.0, 2.1.0 o *. Un invio viene bloccato se il catalogo non ha nessuna versione dentro il suo intervallo.
  • Se dà stile alle pagine di un plugin soltanto con il CSS, non dichiari niente. Il suo CSS ci arriva già.

Stile

Il CSS, e come viene isolato

Scriva normali selettori di classe. All'installazione il suo CSS viene isolato sul suo tema e ogni nome di classe riceve un prefisso valido per tutto il tema, così il .card del suo tema non può scontrarsi con quello di un altro tema.

I nomi di classe delle sezioni devono essere unici fra sezioni. Tutte le sezioni di un tema condividono quell'unico prefisso. Se due sezioni danno entrambe stile a .grid, le regole dell'una ristilizzano l'altra, e un invio con una collisione del genere viene bloccato. Dia alle classi il nome della loro sezione: .picks-grid, .lookbook-grid. Le regole pensate per ogni sezione vanno in theme.css, che è condiviso apposta.
  • Le proprietà vengono confrontate con un elenco. Tutto ciò che viene rifiutato è segnalato quando convalida, mai scartato in silenzio.
  • url() può puntare soltanto alla nostra CDN dei media. I font arrivano dai token dei font: ne nomini uno di Google lì e viene scaricato per lei, senza nessun @import nel suo CSS.
  • Il CSS di una sezione è al massimo di 40 kB, e quello dell'intero tema di 200 kB.

Immagini

Loghi e immagini

I commercianti caricano il loro logo, e un logo SVG resta vettoriale. Al caricamento viene filtrato fino al disegno e messo sempre in un tag img, quindi è sicuro su qualsiasi tema.

Collochi il logo del negozio con { "node": "component", "use": "shop-logo" }. Quando il suo design ha bisogno di una seconda versione, come un logo bianco su una barra scura, aggiunga un'impostazione di tema di tipo image e la passi come src:

{ "node": "component", "use": "shop-logo", "props": { "src": { "get": "theme.logoOnDark" } } }

Dimensioni con il CSS la scatola in cui sta un'immagine, non l'immagine. Le fotografie della sua demo arrivano dal catalogo di esempio sul negozio del tema, quindi non ne spedisce nessuna.

Velocità

Regole di prestazione

Google misura un negozio su un telefono di fascia media con una rete lenta. Queste regole sono lo stesso testo che la CLI scrive in AGENTS.md, e i controlli di pubblicazione pesano la sua home.

Rules for anyone editing this theme, including an AI assistant. Google measures the shop on a mid-range phone on a slow network, so that is the device to build for.

Pictures

  • The picture at the top of the page (hero, first slide) gets "priority": true on its img node. It is what Largest Contentful Paint times, and without it the browser waits to load it. Only that one: every other picture stays lazy.
  • Give every full-width picture a mobileSrc field for phones, a crop that works on a narrow screen, so a phone does not download a desktop banner.
  • Set sizes on any img that is not full width, for example "(min-width: 768px) 33vw, 50vw" for a three-column grid, so the browser picks a smaller file.
  • Give the box a picture sits in a fixed shape in CSS (aspect-ratio), so the page does not jump when it arrives.
  • Do not put the main picture in a CSS background-image: the browser finds it late and cannot pick a size for it.

Fonts

  • At most two families, heading and body. Each one is a separate download.
  • Leave the font tokens at the core stack if the design does not need a web font: that costs nothing at all.

Weight

  • Keep theme.css lean: no unused rules, no copies of the same rule per section.
  • Above the first screen, place only what is needed there. A long home page is fine; a first screen with a slideshow, a carousel and a video is not.
  • Keep each limits realistic. Twenty-four product cards on a home page is twenty-four pictures and a long page to render; eight is usually enough.
  • Avoid heavy CSS effects on large areas (backdrop-filter, big box-shadow, filter: blur), which are slow to draw on a phone.

Checking

Run https://pagespeed.web.dev on the shop's home page and one product page, on Mobile. Aim for Largest Contentful Paint under 2.5 s and Cumulative Layout Shift under 0.1. Fix the first item Lighthouse lists before anything else.

Lingue

Lo scriva in modo che si possa tradurre

Tutto quello che un commerciante potrebbe voler riscrivere dovrebbe essere un campo con un valore predefinito, non una stringa letterale nel markup.

Un campo compare nell'editor del commerciante e nella sua schermata di traduzione, così il suo titolo in inglese diventa il loro in portoghese. Un valore lit resta bloccato in inglese su ogni negozio che installa il suo tema. Tenga lit per cose che non sono parole, come un nome di classe o un valore di disposizione.

AvantiVersioni e revisione →
Formato del tema · WhizzyCommerce