Theme Development
Theme Configuration

Theme Configuration

Configure your theme with theme.json and make it customizable.

theme.json Reference

Complete reference for the theme configuration file.

{
  "name": "My Theme",
  "version": "1.0.0",
  "description": "A beautiful, responsive theme",
  "author": "Your Name",
  "authorUrl": "https://yourwebsite.com",
  "license": "MIT",
  "homepage": "https://github.com/yourname/my-theme",
  
  "assets": {
    "css": ["css/main.css"],
    "js": ["js/main.js"]
  },
  
  "supports": {
    "customLogo": true,
    "customFavicon": true,
    "featuredImages": true,
    "menus": ["primary", "footer"],
    "widgets": ["sidebar", "footer-1", "footer-2", "footer-3"],
    "postFormats": ["standard", "gallery", "video"],
    "customColors": true,
    "darkMode": true
  },
  
  "settings": [
    {
      "key": "accentColor",
      "type": "color",
      "label": "Accent Color",
      "default": "#007bff",
      "section": "colors"
    }
  ],
  
  "layouts": {
    "default": "layouts/main",
    "home": "layouts/home",
    "post": "layouts/single",
    "page": "layouts/page",
    "category": "layouts/archive"
  }
}

Basic Properties

Required Fields

PropertyTypeDescription
namestringDisplay name of the theme
versionstringSemantic version (e.g., "1.0.0")

Optional Fields

PropertyTypeDescription
descriptionstringShort description
authorstringAuthor name
authorUrlstringAuthor's website
licensestringLicense type
homepagestringTheme's homepage or repo
screenshotstringPath to screenshot image
tagsarrayTheme tags for discovery

Assets Configuration

{
  "assets": {
    "css": [
      "css/normalize.css",
      "css/main.css"
    ],
    "js": [
      "js/vendor/lib.min.js",
      "js/main.js"
    ]
  }
}

Assets are loaded in the order specified.


Feature Support

Declare what features your theme supports:

{
  "supports": {
    "customLogo": true,
    "customFavicon": true,
    "featuredImages": true,
    "menus": ["primary", "footer", "mobile"],
    "widgets": ["sidebar", "footer-1", "footer-2"],
    "postFormats": ["standard", "gallery", "video", "quote"],
    "customColors": true,
    "darkMode": true,
    "rtl": true
  }
}

Menus

Declare menu locations:

{
  "supports": {
    "menus": ["primary", "footer", "mobile", "social"]
  }
}

In templates:

{{{ sdk.ui.menu('primary') }}}
{{{ sdk.ui.menu('footer') }}}

Widget Areas

Declare widget areas:

{
  "supports": {
    "widgets": ["sidebar", "footer-1", "footer-2", "footer-3", "before-content", "after-content"]
  }
}

In templates:

<aside class="sidebar">
  {{{ sdk.ui.widgetArea('sidebar') }}}
</aside>

Theme Settings

Make your theme customizable from the admin panel:

{
  "settings": [
    {
      "key": "accentColor",
      "type": "color",
      "label": "Accent Color",
      "description": "Primary color used throughout the theme",
      "default": "#007bff",
      "section": "colors"
    },
    {
      "key": "headerStyle",
      "type": "select",
      "label": "Header Style",
      "options": [
        { "value": "default", "label": "Default" },
        { "value": "centered", "label": "Centered Logo" },
        { "value": "transparent", "label": "Transparent" }
      ],
      "default": "default",
      "section": "header"
    },
    {
      "key": "showAuthor",
      "type": "boolean",
      "label": "Show Author on Posts",
      "default": true,
      "section": "posts"
    },
    {
      "key": "footerText",
      "type": "textarea",
      "label": "Footer Copyright Text",
      "default": "© {{year}} {{siteName}}. All rights reserved.",
      "section": "footer"
    },
    {
      "key": "postsPerPage",
      "type": "number",
      "label": "Posts Per Page",
      "min": 5,
      "max": 50,
      "default": 12,
      "section": "posts"
    },
    {
      "key": "socialLinks",
      "type": "group",
      "label": "Social Links",
      "fields": [
        { "key": "facebook", "type": "text", "label": "Facebook URL" },
        { "key": "twitter", "type": "text", "label": "Twitter URL" },
        { "key": "instagram", "type": "text", "label": "Instagram URL" }
      ],
      "section": "social"
    }
  ]
}

Setting Types

TypeDescriptionOptions
textSingle line textplaceholder, maxLength
textareaMulti-line textrows, maxLength
numberNumeric inputmin, max, step
booleanToggle switch-
selectDropdownoptions
colorColor picker-
imageImage upload-
rangeSlidermin, max, step
groupGrouped fieldsfields

Sections

Organize settings into sections:

{
  "settingSections": [
    { "id": "general", "label": "General" },
    { "id": "colors", "label": "Colors" },
    { "id": "header", "label": "Header" },
    { "id": "footer", "label": "Footer" },
    { "id": "posts", "label": "Posts" },
    { "id": "social", "label": "Social Media" }
  ],
  "settings": [
    { "key": "accentColor", "section": "colors", ... },
    { "key": "headerStyle", "section": "header", ... }
  ]
}

Using Settings in Templates

Access settings via the themeSettings object:

<header style="--accent-color: {{ themeSettings.accentColor }}">
  ...
</header>
 
{% if (themeSettings.showAuthor && post.author) { %}
  <div class="author">By {{ post.author.name }}</div>
{% } %}
 
<footer>
  <p>{{ themeSettings.footerText }}</p>
</footer>

Layout Configuration

Map pages to layout templates:

{
  "layouts": {
    "default": "layouts/main",
    "home": "layouts/home",
    "post": "layouts/single",
    "page": "layouts/page",
    "category": "layouts/archive",
    "tag": "layouts/archive",
    "search": "layouts/search",
    "404": "layouts/error"
  }
}

index.js Configuration

For dynamic configuration, use index.js:

module.exports = function(sdk) {
  return {
    // Custom template helpers
    helpers: {
      formatDate: (date) => {
        return new Date(date).toLocaleDateString('en-US', {
          year: 'numeric',
          month: 'long',
          day: 'numeric'
        });
      },
      
      readTime: (content) => {
        const words = content.replace(/<[^>]*>/g, '').split(/\s+/).length;
        return Math.ceil(words / 200);
      }
    },
    
    // Initialization
    init: async (settings) => {
      // Called when theme is activated
      console.log('Theme activated with settings:', settings);
    },
    
    // Before render hook
    beforeRender: async (context) => {
      // Add data to all templates
      context.currentYear = new Date().getFullYear();
      return context;
    }
  };
};

Use helpers in templates:

<time>{{ helpers.formatDate(post.createdAt) }}</time>
<span>{{ helpers.readTime(post.content) }} min read</span>

Complete Example

{
  "name": "Modern Blog",
  "version": "2.0.0",
  "description": "A clean, modern blog theme with dark mode support",
  "author": "Your Name",
  "license": "MIT",
  
  "assets": {
    "css": ["css/main.css"],
    "js": ["js/main.js"]
  },
  
  "supports": {
    "customLogo": true,
    "customFavicon": true,
    "featuredImages": true,
    "menus": ["primary", "footer"],
    "widgets": ["sidebar", "footer-1", "footer-2", "footer-3"],
    "darkMode": true,
    "customColors": true
  },
  
  "settingSections": [
    { "id": "general", "label": "General" },
    { "id": "colors", "label": "Colors" },
    { "id": "layout", "label": "Layout" },
    { "id": "social", "label": "Social Media" }
  ],
  
  "settings": [
    {
      "key": "primaryColor",
      "type": "color",
      "label": "Primary Color",
      "default": "#007bff",
      "section": "colors"
    },
    {
      "key": "layout",
      "type": "select",
      "label": "Homepage Layout",
      "options": [
        { "value": "grid", "label": "Grid" },
        { "value": "list", "label": "List" },
        { "value": "masonry", "label": "Masonry" }
      ],
      "default": "grid",
      "section": "layout"
    },
    {
      "key": "postsPerPage",
      "type": "number",
      "label": "Posts Per Page",
      "min": 6,
      "max": 24,
      "default": 12,
      "section": "layout"
    },
    {
      "key": "enableDarkMode",
      "type": "boolean",
      "label": "Enable Dark Mode Toggle",
      "default": true,
      "section": "general"
    },
    {
      "key": "facebook",
      "type": "text",
      "label": "Facebook URL",
      "placeholder": "https://facebook.com/yourpage",
      "section": "social"
    },
    {
      "key": "twitter",
      "type": "text",
      "label": "Twitter URL",
      "placeholder": "https://twitter.com/yourhandle",
      "section": "social"
    },
    {
      "key": "instagram",
      "type": "text",
      "label": "Instagram URL",
      "placeholder": "https://instagram.com/yourprofile",
      "section": "social"
    }
  ],
  
  "layouts": {
    "default": "layouts/main",
    "home": "layouts/home",
    "post": "layouts/single",
    "page": "layouts/page",
    "category": "layouts/archive"
  }
}