Theme API
Overview
The Theme API provides comprehensive theme management capabilities including installation, configuration, marketplace integration, and menu management. Themes control the visual appearance and functionality of your Aether CMS site.
Theme Structure
Theme Components
A complete theme includes:
- Templates - HTML/Handlebars templates (
templates/
) - Assets - CSS, JavaScript, images (
assets/
) - Configuration - Theme metadata (
theme.json
) - Partials - Reusable template components (
partials/
)
Theme.json Format
{
"title": "Theme Name",
"description": "Theme description",
"version": "1.0.0",
"author": "Author Name",
"authorUrl": "https://author-website.com",
"tags": ["blog", "minimal", "responsive"],
"license": "GPL-3.0-or-later",
"features": ["responsive", "dark-mode", "seo-optimized"],
"screenshot": "screenshot.png",
"colors": ["#ffffff", "#000000", "#007acc"]
}
Theme Management Endpoints
Get All Themes
GET /api/themes
Success Response (200):
{
"success": true,
"data": [
{
"name": "default",
"path": "content/themes/default",
"info": {
"title": "Default Theme",
"description": "Clean and minimal default theme",
"version": "1.0.0",
"author": "Aether CMS",
"tags": ["default", "minimal"],
"features": ["responsive", "accessible"]
}
}
]
}
Get Active Theme
GET /api/themes/active
Success Response (200):
{
"success": true,
"data": {
"name": "default",
"path": "content/themes/default",
"info": {
"title": "Default Theme",
"version": "1.0.0",
"author": "Aether CMS"
}
}
}
Get Specific Theme
GET /api/themes/{themeName}
Success Response (200):
{
"success": true,
"data": {
"name": "modern-blog",
"path": "/themes/modern-blog",
"info": {
"title": "Modern Blog Theme",
"description": "A modern, responsive blog theme",
"version": "2.1.0",
"author": "Theme Developer",
"authorUrl": "https://developer-site.com",
"tags": ["blog", "modern", "responsive"],
"license": "GPL-3.0-or-later",
"features": ["dark-mode", "seo-optimized", "social-sharing"],
"screenshot": "screenshot.png"
}
}
}
Switch Theme
POST /api/themes/switch/{themeName}
Request Body:
"new-theme-name"
Success Response (200):
{
"success": true,
"data": {
"name": "new-theme-name",
"info": {
"title": "New Theme",
"version": "1.0.0"
}
}
}
Upload Theme
POST /api/themes/upload
Content-Type: multipart/form-data
Form Fields:
theme
- ZIP file containing the theme
Success Response (201):
{
"success": true,
"data": {
"name": "uploaded_theme_123",
"info": {
"title": "Uploaded Theme",
"version": "1.0.0"
}
},
"message": "Theme \"Uploaded Theme\" has been installed successfully"
}
Validation Error (400):
{
"success": false,
"error": "Theme validation failed",
"validationErrors": [
"Missing required field: \"title\"",
"version must be in X.Y.Z format where X, Y, Z are numbers",
"screenshot must be one of: screenshot.jpg, screenshot.png, screenshot.webp"
],
"message": "Theme validation failed: Missing required field: \"title\", version must be in X.Y.Z format"
}
Delete Theme
DELETE /api/themes/{themeName}
Success Response (200):
{
"success": true,
"message": "Theme \"theme-name\" has been deleted successfully"
}
Error Response (400):
{
"success": false,
"error": "Cannot delete the active theme. Please switch to another theme first."
}
Theme Marketplace
Get Marketplace Themes
GET /api/themes/marketplace
Query Parameters:
search
- Search termcategory
- Filter by category/tagsort
- Sort by (name
,date
,version
)
Success Response (200):
{
"success": true,
"data": [
{
"marketplaceName": "modern-portfolio",
"title": "Modern Portfolio",
"description": "A sleek portfolio theme for creatives",
"version": "1.2.0",
"author": "Creative Dev",
"tags": ["portfolio", "creative", "modern"],
"screenshot": "https://cdn.example.com/screenshots/modern-portfolio.png",
"sourceRepo": "creative-dev/modern-portfolio",
"lastUpdated": "2024-01-15T00:00:00.000Z",
"changelog": {
"1.2.0": ["Added dark mode support", "Fixed mobile navigation"],
"1.1.0": ["Improved performance", "Added new layouts"]
}
}
],
"total": 1,
"source": "cdn"
}
Get Marketplace Categories
GET /api/themes/marketplace/categories
Success Response (200):
{
"success": true,
"data": ["blog", "portfolio", "business", "minimal", "modern", "creative"]
}
Install Theme from Marketplace
POST /api/themes/marketplace/install
Request Body:
{
"themeName": "modern-portfolio"
}
Success Response (201):
{
"success": true,
"data": {
"name": "modern-portfolio",
"info": {
"title": "Modern Portfolio",
"version": "1.2.0"
}
},
"message": "Theme \"Modern Portfolio\" installed successfully from marketplace",
"themeCount": 3,
"isAvailable": true
}
Check for Theme Updates
GET /api/themes/marketplace/check-updates
Success Response (200):
{
"success": true,
"data": [
{
"name": "modern-blog",
"title": "Modern Blog Theme",
"currentVersion": "1.0.0",
"latestVersion": "1.2.0",
"marketplaceName": "modern-blog",
"changelog": {
"1.2.0": ["Added dark mode", "Performance improvements"],
"1.1.0": ["Bug fixes", "New templates"]
},
"updateUrl": "creative-dev/modern-blog"
}
],
"hasUpdates": true,
"totalInstalled": 2,
"checkedAt": "2024-01-01T12:00:00.000Z"
}
Update Theme
POST /api/themes/marketplace/update
Request Body:
{
"themeName": "modern-blog"
}
Success Response (200):
{
"success": true,
"data": {
"name": "modern-blog",
"info": {
"title": "Modern Blog Theme",
"version": "1.2.0"
}
},
"message": "Theme \"Modern Blog Theme\" updated successfully from v1.0.0 to v1.2.0",
"changelog": ["Added dark mode", "Performance improvements"]
}
Get Theme Changelog
GET /api/themes/marketplace/changelog/{themeName}/{version?}
Success Response (200):
{
"success": true,
"data": {
"latestVersion": "1.2.0",
"installedVersion": "1.0.0",
"latestChanges": ["Added dark mode", "Performance improvements"],
"fullChangelog": [
{
"version": "1.2.0",
"changes": ["Added dark mode", "Performance improvements"],
"releaseDate": "2024-01-15T00:00:00.000Z"
},
{
"version": "1.1.0",
"changes": ["Bug fixes", "New templates"],
"releaseDate": "2024-01-01T00:00:00.000Z"
}
],
"hasChanges": true
}
}
Menu Management
Get Menu
GET /api/menu
Success Response (200):
{
"success": true,
"data": [
{
"id": "home",
"title": "Home",
"url": "/",
"order": 1,
"parent": null,
"class": "home-link",
"target": "_self"
},
{
"id": "about",
"title": "About",
"url": "/page/about",
"order": 2,
"parent": null
},
{
"id": "services",
"title": "Services",
"url": "/page/services",
"order": 3,
"parent": "about"
}
]
}
Update Menu
PUT /api/menu
Request Body:
[
{
"id": "home",
"title": "Home",
"url": "/",
"order": 1,
"parent": null
},
{
"id": "blog",
"title": "Blog",
"url": "/blog",
"order": 2,
"parent": null
}
]
Success Response (200):
{
"success": true,
"message": "Menu updated successfully"
}
Create Menu Item
POST /api/menu
Request Body:
{
"id": "portfolio",
"title": "Portfolio",
"url": "/portfolio",
"parent": null,
"class": "portfolio-link",
"target": "_self"
}
Success Response (201):
{
"success": true,
"message": "Menu item created successfully"
}
Update Menu Item
PUT /api/menu/{itemId}
Request Body:
{
"title": "Updated Title",
"url": "/new-url",
"class": "updated-class"
}
Success Response (200):
{
"success": true,
"message": "Menu item updated successfully"
}
Delete Menu Item
DELETE /api/menu/{itemId}
Success Response (200):
{
"success": true,
"message": "Menu item deleted successfully"
}
Reorder Menu Items
PUT /api/menu/reorder
Request Body:
{
"orderedIds": ["home", "about", "services", "contact"]
}
Success Response (200):
{
"success": true,
"message": "Menu reordered successfully"
}
Usage Examples
Install Theme from Upload
async function installThemeFromFile(file) {
const formData = new FormData()
formData.append("theme", file)
try {
const response = await fetch("/api/themes/upload", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: formData,
})
const result = await response.json()
if (result.success) {
console.log("Theme installed:", result.data.info.title)
return result.data
} else {
if (result.validationErrors) {
console.error("Validation errors:", result.validationErrors)
}
throw new Error(result.error)
}
} catch (error) {
console.error("Theme installation failed:", error)
throw error
}
}
Switch Active Theme
async function switchTheme(themeName) {
try {
const response = await fetch(`/api/themes/switch/${themeName}`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(themeName),
})
const result = await response.json()
if (result.success) {
console.log("Theme switched to:", result.data.info.title)
// Reload page to apply new theme
window.location.reload()
return result.data
} else {
throw new Error(result.error)
}
} catch (error) {
console.error("Theme switch failed:", error)
throw error
}
}
Browse Marketplace Themes
async function searchMarketplaceThemes(query, category = "", sortBy = "date") {
const params = new URLSearchParams()
if (query) params.append("search", query)
if (category) params.append("category", category)
if (sortBy) params.append("sort", sortBy)
try {
const response = await fetch(`/api/themes/marketplace?${params}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
const result = await response.json()
if (result.success) {
return result.data
} else {
throw new Error(result.error)
}
} catch (error) {
console.error("Marketplace search failed:", error)
return []
}
}
Check and Update Themes
async function checkForThemeUpdates() {
try {
const response = await fetch("/api/themes/marketplace/check-updates", {
headers: {
Authorization: `Bearer ${token}`,
},
})
const result = await response.json()
if (result.success && result.hasUpdates) {
console.log(`${result.data.length} theme updates available`)
return result.data
}
return []
} catch (error) {
console.error("Update check failed:", error)
return []
}
}
async function updateTheme(themeName) {
try {
const response = await fetch("/api/themes/marketplace/update", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ themeName }),
})
const result = await response.json()
if (result.success) {
console.log("Theme updated:", result.message)
if (result.changelog) {
console.log("Changes:", result.changelog)
}
return result.data
} else {
throw new Error(result.error)
}
} catch (error) {
console.error("Theme update failed:", error)
throw error
}
}
Manage Menu
async function updateSiteMenu(menuItems) {
try {
const response = await fetch("/api/menu", {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(menuItems),
})
const result = await response.json()
if (result.success) {
console.log("Menu updated successfully")
return true
} else {
throw new Error(result.error)
}
} catch (error) {
console.error("Menu update failed:", error)
throw error
}
}
async function addMenuItem(menuItem) {
try {
const response = await fetch("/api/menu", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(menuItem),
})
const result = await response.json()
if (result.success) {
console.log("Menu item added")
return true
} else {
throw new Error(result.error)
}
} catch (error) {
console.error("Failed to add menu item:", error)
throw error
}
}
Error Handling
Common Theme Errors
Theme Not Found (404):
{
"success": false,
"error": "Theme not found"
}
Active Theme Deletion (400):
{
"success": false,
"error": "Cannot delete the active theme. Please switch to another theme first."
}
Marketplace Connection (503):
{
"success": false,
"error": "Unable to connect to marketplace. Please try again later."
}
Theme Validation
Themes must include:
- Valid
theme.json
with required fields - Required template files (
layout.html
) - Proper directory structure
- Valid CSS files (
assets/css/style.css
)
For more details, see Theme Structure
Best Practices
- Always backup before switching themes
- Test themes in a staging environment first
- Check compatibility with your content structure
- Review permissions for theme operations
- Monitor updates regularly for security patches