User Docs Developer Docs | |

ThemeService

Registered as service('theme'). Manages theme discovery, activation, and rendering. All public page renders go through this service.

Methods

getActive(): ?object

Returns the currently active theme as an object from the themes table, or null if no theme is active.

$theme = service('theme')->getActive();
// $theme->folder, $theme->name, $theme->version, $theme->status

discover(): void

Scans the themes/ directory for theme_info.json manifests. Inserts new theme records into the themes table. Does not modify existing records. Called from the admin Themes → Discover action.

sync(): void

Reconciles the themes table with the filesystem. Marks themes as unavailable if their directory no longer exists on disk. Called during discover().

view(string $template, array $data = []): string

Renders a .tpl template file within the active theme, merging the provided data with the shared theme data bag.

return service('theme')->view('blog/index.tpl', [
    'posts'      => $posts,
    'pagination' => $pager->links('default', 'bootstrap_full'),
    'page_title' => 'Blog',
]);

The $template path is relative to the active theme's views/ directory. view() handles layout inheritance ({% extends %}), merges shared context, and returns the fully rendered HTML string.

Shared Template Data Bag

ThemeService automatically injects these variables into every template render:

VariableSource
site_nameSettings: App.siteName
site_taglineSettings: App.siteTagline
page_titlePassed by controller (defaults to site_name)
clsActive theme's css_class_mapping from theme_info.json
theme_optionsActive theme's saved options from theme_options table
lang_switcherAvailable languages from languages table
current_userAuthenticated user object or null
auth_groupsCurrent user's group list

Usage in Plugin Controllers

Plugin controllers that render public pages must use service('theme')->view() — never CI4's view() helper directly, as CI4's view() does not support absolute paths or the .tpl engine.

// In a plugin public controller
public function index(): string
{
    $data = [
        'items'      => model('MyPlugin\Models\ItemModel')->getAll(),
        'page_title' => 'My Plugin',
    ];
    return service('theme')->view('myplugin/index.tpl', $data);
}

Plugin templates must be placed inside the active theme's views directory for view() to find them, or the plugin must ship a fallback template and coordinate with theme developers.