Theme API

On this page

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 term
  • category - Filter by category/tag
  • sort - 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

  1. Always backup before switching themes
  2. Test themes in a staging environment first
  3. Check compatibility with your content structure
  4. Review permissions for theme operations
  5. Monitor updates regularly for security patches