Wocart

Theme SDK

A Wocart theme is an Astro storefront. Two published packages power it:

PackageWhat it gives the theme
@wocart/storefrontCommerce: the store's config, products, collections, menus, basket, checkout, delivery, reviews, and the Astro request plumbing
@wocart/themeThe editable layer: component definitions, JSON page documents, composition rules, style and color, settings, the manifest, preview, and an Astro renderer

@wocart/theme is what lets a merchant change a theme's text, images, colors, spacing and section order in Wocart Studio without touching its code. It is a small contract, not a framework: your Astro project, components and CSS stay yours.

This guide follows @wocart/theme 4.1.0 and @wocart/storefront 3.1.0, which read platform v7.

Start with the theme starter. npm create wocart-theme@latest creates a complete theme on both packages: every page a store has, every platform feature, three languages, both hosts, Studio support and its tests. You restyle and extend it instead of writing the plumbing. The guide's examples come from it. You can also build a theme from scratch with the two packages; the starter is the faster way to the same result.

Do you need it?

You are building…Use
A storefront for one shop, changed only by you in code@wocart/storefront and Astro. Skip this package.
A theme a merchant edits in Wocart StudioBoth packages. Start with the starter.
A theme for many stores, a client, or the marketplaceThe starter, plus the manifest, testing and production pages

An editable theme costs more setup than a fixed one, because every editable choice is declared, stored and checked. That cost buys a theme any store can install and any merchant can change safely.

How it works in one picture

Code
code (you write it) data (the store saves it) ┌──────────────────────────┐ ┌────────────────────────────┐ │ defineComponent(...) │ │ page document (JSON) │ │ fields, slots, load │ │ { version, surface, │ │ defineTheme(...) │ │ sections: [instances] }│ │ surfaces, areas, │ │ theme settings (JSON) │ │ settings, content │ │ text edits per language │ └────────────┬─────────────┘ └──────────────┬─────────────┘ │ themeManifest() │ storefront client ▼ ▼ /wocart-theme.json ──► Wocart Studio resolveSurfaceDocument() (what is editable) writes data ──► InstanceView renders your .astro components
  • Code is the catalog. Each component you want editable gets a definition: its type, its fields, where it may go, and an optional server-side load.
  • Data is the page. A page is a document: an ordered list of component instances with their saved values. The theme ships a default document for every page; a store may save its own.
  • The manifest connects them. It is the code half turned into JSON, so Wocart Studio knows what can be edited without running your theme.
  • Reading never breaks a page. A saved document is untrusted: the SDK repairs what it can, reports the rest, and never throws the page away over one bad section.

Words you will see

WordMeaning
ComponentA reusable piece of a page, such as a hero, a product grid or a header
DefinitionThe code that makes a component editable: defineComponent({...})
FieldOne thing a merchant can change on a component: a title, an image, a number
InstanceOne placed copy of a component in a document, with its own id and values
SectionAn instance at the top level of a page
BlockAn instance inside another component's slot
SlotA named place inside a component where blocks may go
DocumentThe JSON that composes one page: { version, surface, sections }
SurfaceWhich page a document fills: home, product, area:header …
AreaA part every page shares, such as the header, composed and edited once
SettingA choice for the whole store, such as its color schemes or the header menu
Content packThe theme's own text, one flat map of keys to strings per language
ManifestThe JSON description of everything a theme makes editable
Theme keyThe theme's permanent identity on the platform; saved edits are stored under it

What the package guarantees

  • One typed definition per component. Field keys, kinds and select options keep their literal types; the component's props are derived from the same definition (InferProps), so the two cannot drift.
  • Safe reads. parsePageData, validatePageData and resolveSurfaceDocument turn any saved value into a renderable page plus a list of issues. Only a broken envelope makes a document unusable, and then the theme's default renders.
  • Layout rules that hold. Slots, allowed types, required and fixed blocks, placement and limits are applied by the same code for the renderer, the reader and every editor.
  • Safe values. Links, colors, images, rich text, style and color schemes are closed formats. A saved value cannot carry a javascript: link, raw CSS or HTML.
  • One renderer. InstanceView.astro resolves values, runs load, renders your component, and places its blocks.
  • The editor plumbing. The manifest, document operations, preview markers, the preview bridge, settings, content packs and plural messages.

What it does not do

  • It does not fetch commerce data. Reads go through the @wocart/storefront client a load receives.
  • It does not save anything. Wocart Studio and the platform write documents, settings and text edits; a theme only reads them.
  • It does not upload images, define your CSS, or replace Astro.

The rules every theme follows

Each rule below exists because breaking it fails a merchant or a shopper in a way a test of the theme alone would not show. The Enforced by column says what catches a break: the SDK (for every theme), or the starter's tests (a theme made with the starter runs them with npm test; a theme built from scratch copies them).

RuleWhyEnforced by
Pin @wocart/theme and @wocart/storefront exactly, 4.x with 3.xA theme on @wocart/storefront 2.x reads a v7 store as unreadablenpm's peer range
Build for both hosts from the same code: @astrojs/cloudflare by default, @astrojs/vercel with DEPLOY_TARGET=vercel, session: false, and no image service that ships native binariesWocart Cloud deploys a store's theme to Cloudflare or to Vercel; a theme that builds for one only cannot be deployed to the otherBoth builds (npm run build, npm run build:vercel); the starter's guard test
Create the store client per request, on the server only, with theme: <your key>Without theme, the store's text edits, settings and documents for your theme never arrive; a shared client mixes languagescreateStoreClient throws MISSING_CONFIGURATION on an empty URL or key; the starter's guard test (one client factory)
Render unavailableStoreConfig(…) when the store cannot be read; never a config written by handA hand-written config falls behind the config's shape and can look like a working checkoutThe fallback option of resolveStoreRequest; the starter's guard test
Compose every platform page type as a surface with one required main section: home, catalog, category, collection, product, text page, landing, checkout, thank-you, order tracking, search, contactA page type with no surface cannot be composed or previewed in Studio (previewTarget answers null, so the preview is a 404)The starter's contract test
Read saved data through resolveSurfaceDocument and resolveThemeSettingsSaved data is untrusted; one bad section must never break a pageThe SDK repairs and reports; it never throws
Never write: no endpoint saves a document, a setting or merchant textStudio is the only writer; a theme that writes bypasses its checksThe platform's API has no such endpoint
Every shopper-facing word comes from a content pack, in every language the theme declares, with plural messages through formatMessageA hard-coded word shows French to an Arabic shopper; a count needs its language's plural formsvalidateThemeDefinition (labels, contentKeys), pluralFormIssues; the starter's copy test
No theme word states a fact about a store: its delivery reach, hours, phone, address or pricesIt is true of one store and false of the nextThe starter's copy test catches the common cases (a reach, a period, a percentage, hours, a phone call); review the rest
Build every platform link with storefrontPath and localizeHref; render menu items' href as givenA hand-written path breaks when a page moves or a language is addedThe starter's guard test
Reach the store's WhatsApp only through whatsAppContact, behind one module holding your wordsA hand-written wa.me link ignores the merchant's number, texts and message rulesThe starter's guard test
Take colours from the page's or section's color schemeA hard-coded colour ignores the merchant's palettecolorScheme fields and schemeClass; the starter's contract and guard tests
Resolve images from media keys with config.mediaA hard-coded host breaks on another store's media hostvalidateThemeDefinition refuses an image default
Keep Zod and the server entries out of browser codeA schema ships Zod to every shopper; /server would carry the store keyThe starter's guard tests
Never rename the theme key, a component type or a field key once stores use themEvery saved edit is keyed by themdiffThemeManifests reports a breaking change

The starter, file by file lists each test and the command that runs it.

Install

The starter installs both packages for you. To add them to a project of your own:

TerminalCode
npm install --save-exact @wocart/theme@4.1.0 @wocart/storefront@3.1.0 zod
RequirementValue
Node22.12 or newer
Module formatESM only
@wocart/storefrontRequired peer of @wocart/theme, ^3.0.0
astroOptional peer, ^7.0.0 — required for the ./astro renderer, which every Astro theme uses
zod^4.4.3: a required peer of @wocart/storefront, a dependency of @wocart/theme. Validation runs on the server and in the build; keep it out of browser code

Where to go next

If you want to…Read
Create a complete theme and run itQuick start with the starter
Find your way around itThe starter, file by file
Restyle it, change its words, add a sectionMake it your own
Build a theme from an empty projectBuild from scratch
Choose the right field for a valueFields
Nest blocks, require an order form, add presetsComposition
Understand surfaces, areas, documents and renderingPages and rendering
Give merchants spacing and color controlsStyle and color
Translate the theme and add store-wide settingsSettings and copy
Let Studio read and edit the themeThe manifest and Preview
Show store images at the right sizeImages
Prove the theme worksTesting a theme
Ship and upgrade itProduction and upgrades
Decode an issue codeIssues and fixes
See every exportPublic API surface and the generated API reference

Choose the theme key once

defineTheme({ key }) is the theme's identity. Merchant text edits, page documents and settings are stored under it, and a storefront receives them only when its client passes the same key. Renaming it orphans every edit made under the old name.