Back to Main Site

Theme Development: Getting Started

Last updated on Jun 24, 2026 01:43

PolyCMS uses a highly flexible, Blade-based theme engine. While the Admin Panel is a Vue 3 SPA, the public-facing frontend relies on traditional, ultra-fast Server-Side Rendered (SSR) Blade templates by default (though it fully supports Headless API-driven frontends as well).

This guide covers the architecture of a PolyCMS Theme and how to build one from scratch.

1. Directory Structure

All themes reside in the themes/ directory.

Let's look at the structure of a standard theme, such as the core flexiwhite blueprint:

themes/
└── flexiwhite/
    ├── theme.json           # The Theme Manifest
    ├── screenshot.png       # 800x600 preview image for the Admin panel
    ├── functions.php        # Optional: PHP logic, Hook registration
    ├── resources/
    │   └── views/           # Blade templates
    │       ├── layouts/
    │       │   └── app.blade.php  # The master wrapper
    │       ├── partials/
    │       └── templates/   # Specialized block templates (Landing pages, etc.)
    └── public/              # Compiled CSS/JS and Images

2. The Theme Manifest (theme.json)

To register a theme with the system, you must define a theme.json file. The ThemeManager uses this to identify the theme and expose its available templates to the Admin UI.

{
  "name": "FlexiWhite",
  "slug": "flexiwhite",
  "version": "1.0.0",
  "author": "Polyx Team",
  "description": "A clean, whitespace-heavy corporate theme.",
  "role": "main",
  "templates": {
    "posts": {
      "full-width": "Full Width No Sidebar",
      "gallery": "Gallery Focus Layout"
    },
    "pages": {
      "landing": "Marketing Landing Page",
      "contact": "Contact Form Layout"
    }
  }
}

Main Themes vs. Sub Themes

Notice the "role": "main" key. PolyCMS implements a Multi-Theme Architecture:

Main Themes (role: main): Provide the global layout (app.blade.php) and site-wide CSS. Only one can be active at a time.

Sub Themes (role: sub): Provide specialized templates (like a unique checkout flow or a Black Friday landing page). You can activate multiple Sub Themes simultaneously. Their templates will override the Main Theme when assigned to specific posts or pages.

3. The Master Layout (app.blade.php)

Every Main Theme must have a master layout file located at resources/views/layouts/app.blade.php. This file defines the HTML skeleton.

Critical Requirements: To ensure modules and plugins can inject their necessary CSS and JavaScript (like the Cookie Consent banner or Analytics scripts), your layout must include the @stack directives.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <!-- Render SEO Meta Tags dynamically -->
    <title>@yield('meta_title', config('app.name'))</title>
    
    <!-- Include Theme CSS -->
    <link rel="stylesheet" href="{{ theme_asset('css/style.css') }}">
    
    <!-- CRITICAL: Allow modules to inject CSS -->
    @stack('theme-styles')
</head>
<body>
    
    @include('theme::partials.header')

    <main>
        <!-- Render the specific page/post content here -->
        @yield('content')
    </main>

    @include('theme::partials.footer')

    <!-- CRITICAL: Allow modules to inject JS -->
    @stack('theme-scripts')
</body>
</html>

4. The theme_asset() Helper

When linking to CSS, JS, or images stored in your theme's public/ directory, always use the theme_asset() helper function rather than Laravel's standard asset().

<!-- CORRECT -->
<img src="{{ theme_asset('images/logo.svg') }}" alt="Logo">

<!-- INCORRECT -->
<img src="{{ asset('themes/flexiwhite/public/images/logo.svg') }}" alt="Logo">

theme_asset() automatically resolves the correct path based on the currently active theme and handles caching.

Next Steps

With your manifest and layout complete, your theme can now be activated from the Admin Panel under Appearance > Themes.

To dive deeper, explore how to Register Widget Areas or use functions.php to tap into the Hook System.


PolyCMS is an open-source content management system for modern web applications, inspired by the WordPress plugin and theme ecosystem but built on top of the Laravel framework. It is designed to provide a complete foundation for content publishing, e-commerce, multi-language support, and extensible module architecture — powered by a Vue 3 admin panel with data served entirely through RESTful APIs.

Whether you're building a blog, a documentation site, an online store, or a multi-tenant SaaS platform, PolyCMS aims to give you a comprehensive starting scaffold so you can ship quickly and extend easily through integrated modules and themes. In particular, themes in PolyCMS follow a multi-theme architecture — one Main theme and an unlimited number of Sub themes can run side by side on the same installation.

We hope this ready-made foundation proves useful for building your next website, blog, or web app, saving you from having to start completely from scratch.