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
- Zip your theme folder
- Go to Admin Panel → Appearance → Themes
- Click Upload Theme
- Select your zip file
- Click Activate to use your theme
Next Steps
- Learn Template Syntax - Master the templating language
- Template Variables - Access all available data
- Theme Configuration - Add customization options
- Examples - See complete theme examples