Skip to content

Getting started

Scaffold a minimal theme, preview it on a development site, and validate it with the CLI.

1. Create the files

A theme is a folder of Twig and config. A minimal theme:

my-theme/
  theme.json
  pages.twig
  layouts/
    app.twig
  templates/
    home.twig
  partials/
    seo.twig
  config/
    settings_schema.json
    menu.json
    templates.json
  css/
    app.css

theme.json — the manifest that identifies your theme on the platform. The same contract is used everywhere: CLI publishing and private zip uploads both read the theme's slug, name, and version from it:

json
{
  "slug": "my-theme",
  "name": "My Theme",
  "version": "1.0.0",
  "description": "A minimal starter theme."
}

layouts/app.twig — the shell every template extends:

twig
<!doctype html>
<html lang="{{ app.locale }}">
  <head>
    <meta charset="utf-8">
    <title>{{ general_settings.site_name ?? 'Stayblox' }}</title>
    {% include 'partials/seo.twig' %}
    <link rel="stylesheet" href="{{ theme_asset('css/app.css') }}">
  </head>
  <body style="--brand: {{ settings.primary_color ?? '#4f46e5' }}">
    <nav>
      {% for item in menu_items %}
        <a href="{{ item.resolved_url }}">{{ item.label }}</a>
      {% endfor %}
    </nav>
    {% block content %}{% endblock %}
  </body>
</html>

templates/home.twig:

twig
{% extends 'layouts/app.twig' %}
{% block content %}
  <h1>{{ 'nav.home' | trans }}</h1>
  {% for unitType in featured_unit_types %}
    <article>
      <h2>{{ unitType.name }}</h2>
      <a href="{{ route('home') }}">{{ t('view_details') }}</a>
    </article>
  {% endfor %}
{% endblock %}

pages.twig — the dispatcher that renders CMS pages (blog posts, custom pages) by including the matching template. Marketplace validation requires it:

twig
{% extends 'layouts/app.twig' %}
{% block content %}
  {% include 'templates/' ~ template.slug ~ '.twig' %}
{% endblock %}

config/settings_schema.json — the host-configurable settings (sections of fields; see Theme settings):

json
[
  {
    "name": "General",
    "fields": [
      { "id": "primary_color", "type": "color", "label": "Primary Color", "default": "#4f46e5" },
      { "id": "show_footer", "type": "toggle", "label": "Show Footer", "default": true }
    ]
  }
]

config/menu.json (navigation) and config/templates.json (page templates) round out the config — see the reference layout.

css/app.css:

css
body { font-family: system-ui, sans-serif; }
a { color: var(--brand); }

2. Preview on a development site

Zip the contents so layouts/ sits at the archive root:

bash
cd my-theme
zip -r ../my-theme.zip .

In a development site, go to Themes → Manage themes → Upload theme and upload the .zip — the theme's slug, name, and version come from theme.json. Activate it, then open the storefront. Use the in-browser code editor to tweak templates and assets, and the theme settings page to see your settings_schema.json rendered as a form.

3. Validate with the CLI

When you're aiming for the marketplace, install the Stayblox CLI and validate from the theme directory:

bash
npm install -g @stayblox/cli
stayblox login
stayblox theme validate

The report tells you exactly what the marketplace requires (structure, valid config JSON, Twig lint with line numbers) before you ever publish. When it passes, stayblox theme push publishes a private draft and stayblox theme push --submit sends it for review — see Publishing.

Next

© Stayblox — Developer Platform