Theme Development
Getting Started

Getting Started with Themes

Create your first custom theme for FeedGen CMS.

Prerequisites

  • A FeedGen CMS website
  • Basic knowledge of HTML and CSS
  • A text editor

Step 1: Create Theme Folder

Create a new folder for your theme with this structure:

my-theme/
├── theme.json          # Theme manifest (required)
├── index.js            # Theme entry point (required)
├── views/
│   ├── layouts/
│   │   └── main.html   # Main layout wrapper
│   ├── pages/
│   │   ├── home.html   # Homepage
│   │   ├── post-detail.html
│   │   ├── posts.html
│   │   ├── category-detail.html
│   │   ├── categories.html
│   │   ├── author-detail.html
│   │   ├── search.html
│   │   └── error.html
│   └── partials/
│       ├── head.html
│       ├── header.html
│       ├── footer.html
│       └── post-card.html
└── assets/
    ├── css/
    │   └── main.css
    ├── js/
    │   └── main.js
    └── images/

Step 2: Create theme.json

The manifest file defines your theme:

theme.json
{
  "name": "My Theme",
  "version": "1.0.0",
  "description": "A custom theme for my website",
  "author": "Your Name",
  "license": "MIT",
  
  "supports": {
    "customLogo": true,
    "customColors": true,
    "widgets": ["sidebar", "footer"],
    "menus": ["primary", "footer"]
  },
  
  "assets": {
    "css": ["css/main.css"],
    "js": ["js/main.js"]
  }
}

Step 3: Create index.js

The entry point for your theme:

index.js
module.exports = function(sdk) {
  // Theme initialization
  
  return {
    // Optional: Custom template helpers
    helpers: {
      formatPrice: (price) => `$${price.toFixed(2)}`,
      truncate: (text, length) => {
        if (text.length <= length) return text;
        return text.substring(0, length) + '...';
      }
    }
  };
};

Step 4: Create Main Layout

The layout wraps all pages:

views/layouts/main.html
<!DOCTYPE html>
<html lang="{{ settings.language || 'en' }}">
<head>
  {{{ include('partials/head') }}}
</head>
<body>
  {{{ include('partials/header') }}}
  
  <main>
    {{{ content }}}
  </main>
  
  {{{ include('partials/footer') }}}
</body>
</html>

Step 5: Create Head Partial

views/partials/head.html
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ pageTitle || settings.siteName }}</title>
<meta name="description" content="{{ pageDescription || settings.siteDescription }}">
 
{# Theme CSS #}
<link rel="stylesheet" href="/themes/my-theme/assets/css/main.css">
 
{# Favicon #}
{% if (settings.favicon) { %}
<link rel="icon" href="{{ settings.favicon }}">
{% } %}

Step 6: Create Header Partial

views/partials/header.html
<header class="site-header">
  <div class="container">
    {# Logo #}
    <a href="/" class="logo">
      {% if (settings.logo) { %}
        <img src="{{ settings.logo }}" alt="{{ settings.siteName }}">
      {% } else { %}
        {{ settings.siteName }}
      {% } %}
    </a>
    
    {# Navigation #}
    <nav class="main-nav">
      {{{ sdk.ui.menu('primary') }}}
    </nav>
  </div>
</header>

Step 7: Create Homepage

views/pages/home.html
{# Hero Section #}
<section class="hero">
  <h1>{{ settings.siteName }}</h1>
  <p>{{ settings.siteDescription }}</p>
</section>
 
{# Latest Posts #}
{% if (latestPosts && latestPosts.length > 0) { %}
<section class="latest-posts">
  <h2>Latest Posts</h2>
  
  <div class="posts-grid">
    {% latestPosts.forEach(post => { %}
      {{{ include('partials/post-card', { post: post }) }}}
    {% }) %}
  </div>
</section>
{% } %}
 
{# Categories #}
{% if (categories && categories.length > 0) { %}
<section class="categories">
  <h2>Categories</h2>
  
  <div class="categories-grid">
    {% categories.forEach(category => { %}
      <a href="{{ category.url }}" class="category-card">
        {% if (category.image) { %}
          <img src="{{ category.image }}" alt="{{ category.name }}">
        {% } %}
        <span>{{ category.name }}</span>
      </a>
    {% }) %}
  </div>
</section>
{% } %}

Step 8: Create Post Card Partial

views/partials/post-card.html
<article class="post-card">
  {% if (post.featuredImage) { %}
    <a href="{{ post.url }}" class="post-card__image">
      <img src="{{ post.featuredImage }}" alt="{{ post.title }}" loading="lazy">
    </a>
  {% } %}
  
  <div class="post-card__content">
    {% if (post.category) { %}
      <a href="{{ post.category.url }}" class="post-card__category">
        {{ post.category.name }}
      </a>
    {% } %}
    
    <h3 class="post-card__title">
      <a href="{{ post.url }}">{{ post.title }}</a>
    </h3>
    
    {% if (post.excerpt) { %}
      <p class="post-card__excerpt">{{ post.excerpt }}</p>
    {% } %}
    
    <div class="post-card__meta">
      <span>{{ sdk.utils.formatDate(post.createdAt) }}</span>
    </div>
  </div>
</article>

Step 9: Upload Your Theme

  1. Zip your theme folder
  2. Go to Admin Panel → Appearance → Themes
  3. Click Upload Theme
  4. Select your zip file
  5. Click Activate to use your theme

Next Steps