Všetky príručky

Vývoj vlastnej témy

Súborová štruktúra témy, registrácia sekcií, i18n, SSR build a príkazy make:theme, theme:export a theme:import.

Pre: Vývojár

Téma je priečinok v resources/themes/<slug>/ s React sekciami, JSON schémami nastavení a jedným registrom, ktorý ich spája. Tento článok je pre vývojára, ktorý stavia novú tému alebo upravuje existujúcu — ako obchodník sekcie v hotovej téme nastavuje, opisuje Editor témy — základy a Referencia sekcií editora témy.

1. Štruktúra priečinka

resources/themes/<slug>/
  theme.json          # meno, verzia, dostupné layouty, CSS/JS assety, settings_schema (globálna paleta a písma)
  registry.ts          # jediný súbor, ktorý mapuje section type → React komponent
  layouts/*.json       # zoznam sekcií pre danú stránku (home, product, cart, checkout, ...)
  sections/*.json       # schéma nastavení KAŽDÉHO typu sekcie (settings + volby)
  sections/<Name>/      # React implementácia (index.tsx = komponent, žiadny samostatný "VariantA.tsx" wrapper)
  templates/            # celostránkové šablóny (napr. ProductsListing)
  pages/                # stránky bez sekcií (Cart, Checkout, Account) — často znovupoužité z @shop/core
  menus.json             # predvolené menu
  assets/               # theme.css a ďalšie statické súbory

layouts/*.json určuje poradie a nastavenia sekcií na danej stránke; sections/*.json určuje, aké nastavenia sekcia vôbec ponúka (typ poľa, predvolená hodnota, možnosti výberu). Editor témy v administrácii oba súbory spája — layout ukladá hodnoty, schéma kreslí formulár.

2. Registrácia cez createRegistry

registry.ts sa musí stavať cez createRegistry() z @shop/core — nie ako obyčajný exportovaný objekt:

import { createRegistry } from '@shop/core/createRegistry';
import Header from './sections/Header/index';
import Hero from './sections/Hero/index';
// …

export default createRegistry({
  sections: { header: Header, hero: Hero /* … */ },
  templates: { /* … */ },
  pages: { /* … */ },
});

createRegistry() doplní každú povinnú šablónu/slot/stránku z @shop/core, ktorú téma sama nedefinuje — takže chýbajúca položka nezostane nepovšimnutá. Bez neho by chýbajúci záznam zostal len detegovateľný (ThemeRenderer vykreslí prázdnu sekciu namiesto chyby), nie nemožný. Kontrakt kontroluje test resources/js/__tests__/themeRegistryContract.test.ts, spúšťaný v npm test — nie build (vite build len odstraňuje typy, typová chyba mu neprekáža).

Pozor: Import komponentu vždy so /index na konci (./sections/Header/index, nie ./sections/Header). Na macOS (case-insensitive súborový systém) sa bez neho môže cesta zhodnúť s sections/header.json a naimportuje sa schéma namiesto komponentu.

3. Preklady v sekciách

Textové pole, ktoré má byť preložiteľné, nesie vedľa seba pole <pole>_translations s kľúčmi podľa locale:

{
  "search_placeholder": "Vyhľadať produkt...",
  "search_placeholder_translations": {
    "cs": "Vyhledat produkt...",
    "en": "Search products..."
  }
}

SectionLocalizer na storefronte vymení hodnotu podľa aktívneho jazyka zákazníka. Ak pole prekladateľné pole má, ale niektorá jeho inštancia sibling _translations nemá, alebo pokrýva iný súbor jazykov než ostatné preklady na stránke, čitateľ v danom jazyku dostane pôvodný (zle prepnutý) text — ticho, bez chyby.

4. Guard skripty (musia prejsť pred zaradením zmeny)

SkriptČo kontroluje
php scripts/theme-variant-guard.phpjednodizajnové témy (nutrition-pro, power-supplements, velur) nesmú mať v žiadnej sekcii pole variant — pozri §5
php scripts/theme-i18n-guard.phpkaždé prekladateľné pole má _translations všade, kde sa objaví, a všetky pokrývajú rovnakú množinu jazykov
php scripts/theme-integrity-guard.phpkaždá sekcia v layouts/*.json, každá schéma v sections/*.json, každý inzerovaný variant a (pri ručných registroch) celý pages kontrakt sa dá naozaj vykresliť
php artisan theme:validate <slug>statická kontrola kontraktu sekcia/registry/layout bez potreby tenanta alebo prehliadača

5. Jednodizajnové témy (Nutrition Pro, Power Supplements, Velur)

Tieto tri témy sú zámerne jednodizajnové — sekcia nemá prepínač variantu, index.tsx JE komponent (žiadny VariantA.tsx wrapper okolo). Pridanie poľa variant do schémy takejto sekcie je regresia, nie funkcia navyše, a theme-variant-guard.php na to spadne.

6. SSR build

Po každej zmene .tsx súboru v téme (sekcia, šablóna, stránka) spustite:

npm run build:ssr

a reštartujte SSR daemona. Bez toho SSR naďalej vracia starý strom komponentov — na storefronte sa to prejaví ako nesúlad medzi serverovým a klientským vykreslením (hydration mismatch) pri prvom načítaní.

7. Príkazy pre prácu s témami

# Nová téma naklonovaná z existujúcej (predvolene zo `space`)
php artisan make:theme acme --display="Acme Shop" --from=space

# Export témy jedného obchodu (nastavenia, layouty, menu, obrázky) do .zip
php artisan theme:export moj-eshop --output=storage/app/theme-exports/moj-eshop.zip

# Export vrátane katalógu a CMS obsahu (pri odovzdávaní hotového klientskeho buildu)
php artisan theme:export moj-eshop --with-content

# Import bundlu do cieľového obchodu
php artisan theme:import cielovy-eshop storage/app/theme-exports/moj-eshop.zip

theme:import --with-content zmaže existujúci obsah cieľového tenanta a nahradí ho obsahom z bundlu — príkaz odmietne bežať, ak cieľový tenant už má objednávky, práve preto, že ide o nezvratnú operáciu vhodnú len pre obchod, ktorý ešte nezačal predávať.

Časté problémy

  • Sekcia sa v administrácii nezobrazí, hoci je v layout JSON. Skontrolujte, či je zaregistrovaná v registry.ts presne pod rovnakým type, aký má v layouts/*.json a sections/*.json — ThemeRenderer chýbajúcu položku vykreslí ako prázdnu, nie ako chybu.
  • Zmena vzhľadu sa neprejavila po nasadení. Chýba npm run build:ssr a reštart SSR daemona po zmene .tsx súboru.
  • `theme-variant-guard.php` padá na jednodizajnovej téme. Niekto pridal pole variant do schémy sekcie tejto témy — odstráňte ho, dizajn je zámerne jeden.
  • Čeští zákazníci vidia slovenský text uprostred stránky. Prekladateľné pole má chýbajúci alebo neúplný _translations blok — doplňte ho pre všetky jazyky, ktoré má obchod aktívne.
  • `theme:import --with-content` odmietne spustiť sa. Cieľový tenant už má objednávky — operácia je určená len pre obchod, ktorý ešte nezačal predávať.

Súvisí

Bola táto stránka užitočná?