Crear un tema desde cero
Un tema es una aplicación web independiente. No corre dentro de la tienda: habla con ella por HTTP, como lo haría cualquier cliente.
Eso significa que puedes usar el stack que quieras — Next, Astro, Vite, Nuxt, SvelteKit, Remix— siempre que cumplas el contrato.
Lo mínimo
Sección titulada «Lo mínimo»Una carpeta dentro de themes/ con esto:
mi-tema/ theme.json ← obligatorio: quién eres y qué traes settings.schema.json ← qué se puede personalizar desde el panel sections.schema.json ← qué bloques se pueden recomponer (opcional) demo/contenido.json ← contenido de ejemplo (opcional, muy recomendable) .env.example ← qué variables necesitasSin theme.json el panel no lo ve.
theme.json
Sección titulada «theme.json»Declara qué eres y qué sabes hacer:
{ "contract": "2.0", "id": "mi-tema", "name": "Mi Tema", "version": "1.0.0", "runtime": { "stack": "next", "commands": { "install": "npm install", "dev": "npm run dev", "build": "npm run build" }, "env": [ { "name": "NEXT_PUBLIC_PCC_BACKEND_URL", "required": true }, { "name": "NEXT_PUBLIC_PCC_PUBLISHABLE_KEY", "required": true } ] }, "capabilities": { "pages": ["home", "catalog", "product", "cart", "checkout", "order-confirmation"], "blocks": ["hero", "bestsellers", "newsletter"], "locales": ["es"] }}capabilities.pages no es decorativo: el panel avisa si dices que tienes
checkout y no declaras página de confirmación de pedido. Un cliente que paga y
no aterriza en ninguna parte es un carrito perdido.
La lista completa de campos está en el contrato de tema.
Hablar con la tienda
Sección titulada «Hablar con la tienda»Dos datos, y el segundo es el que más se olvida:
COMMERCE_URL=https://mitienda.comCOMMERCE_KEY=pk_...Sin la clave publicable tu tema arranca y no ve ni un producto, y el error no dice que falte una clave. Es el fallo número uno al montar un tema.
Puedes hablar con la Store API a pelo con fetch, o usar el adaptador del
contrato de datos:
import { createCommerce } from "@pcreative/commerce-contract/api"
const commerce = createCommerce({ baseUrl: process.env.COMMERCE_URL, publishableKey: process.env.COMMERCE_KEY, countryCode: "es",})El adaptador usa fetch a secas, sin ningún SDK: un SDK presupone navegador, y
eso es justo lo que impediría que un tema Astro o un runtime edge usaran el
mismo código.
Contenido de ejemplo
Sección titulada «Contenido de ejemplo»Un tema vacío no se puede juzgar. Pon un demo/contenido.json con categorías y
productos:
{ "categorias": [{ "handle": "tartas", "nombre": "Tartas" }], "productos": [{ "handle": "tarta-chocolate", "titulo": "Tarta de chocolate", "categoria": "tartas", "imagenes": ["https://…"], "variantes": [{ "titulo": "8 raciones", "precio": 28, "sku": "TC-8" }] }]}Es agnóstico de la plataforma: describe productos, no tablas de nadie. El panel lo valida antes de importar y te dice qué trae.
Personalización desde el panel
Sección titulada «Personalización desde el panel»En settings.schema.json declaras qué se puede tocar sin programar: colores,
tipografías, textos, imágenes. El panel genera la pantalla sola a partir del
esquema — no tienes que escribir interfaz.
Cuatro errores que se repiten
Sección titulada «Cuatro errores que se repiten»«0 productos» → falta la clave publicable, o apunta a otro canal de venta.
CORS bloqueando todo → tu dirección no está en STORE_CORS del backend.
Cuando montes el tema en un puerto nuevo, acuérdate.
Precios a NaN → la Store API devuelve unit_price y currency_code; si
tu interfaz lee price y currency, falta el mapeo. Es silencioso.
El checkout no crea el pedido → falta algún paso. El contrato exige, por
este orden: setEmail, setAddresses, setShippingMethod (uno por paquete si
hay marketplace), selectPaymentMethod y complete. Cada uno devuelve el
carrito actualizado; el que falle te dice qué falta.