Themes Are Now Optional in Djebel
Every file your app loads takes time. Every directory it checks adds a little bit of delay. If you're building an API or a headless backend, loading a full theme with templates and layout files is work your app doesn't need to do.
That's why themes in Djebel are now fully optional.
If your site doesn't need a theme, just skip it. No theme files to scan. No templates to resolve. Your plugins deliver content directly through hooks and that's it.
Why This Matters for Performance
Djebel is built to power a large number of sites. At that scale, every bit of speed matters.
When a theme loads, the framework resolves the theme directory, looks for templates, and runs several hooks like app.core.theme.setup. If functions.php loading is enabled, that file gets included too along with its own hooks.
For an API endpoint, none of that does anything useful. It's extra work with no benefit.
When you run without a theme, Djebel skips all of it. The themes.php file is never loaded. Your request goes straight from plugins to content delivery. Faster and lighter.
How to Enable a Theme
If your site needs a theme, just add a [theme] section to your app.ini file:
[site]
site_title = My Website
description = A Djebel-powered site
[theme]
theme_id = djebel
The theme_id tells Djebel which theme to load. It checks a few keys in order: theme.theme, theme.theme_id, site.theme_id, and site.theme. If any of them has a value, that theme gets loaded.
How to Run Without a Theme
There are several ways to turn off theme loading. Pick whichever works best for you.
Set load_theme to 0 in app.ini
The most explicit way. Add load_theme = 0 to the [theme] section of your app.ini:
[theme]
load_theme = 0
Clear and obvious. Anyone reading your config knows exactly what's going on.
Comment Out the theme_id
If you already have a theme configured and want to quickly disable it, just comment out the theme_id line with ; or #:
[theme]
;theme_id = djebel
or
[theme]
#theme_id = djebel
This is handy for testing. You keep the value around so you can bring it back later by removing the comment character.
Skip the Theme Section Entirely
Another simple approach. Just don't include a [theme] section and don't set any theme_id:
[site]
site_title = My API Service
description = Headless backend - no theme needed
[meta]
default.title = My API Service
[app]
env = dev
No theme_id set means no theme loaded. That's all there is to it.
Use an Environment Variable
You can also set the DJEBEL_APP_CORE_THEME_LOAD_THEME environment variable:
export DJEBEL_APP_CORE_THEME_LOAD_THEME=0
You can use 0 or false as the value. Both work. There's also a shorter form:
export APP_CORE_THEME_LOAD_THEME=0
If you're running Apache, you can set it in your .htaccess or virtual host config:
SetEnv DJEBEL_APP_CORE_THEME_LOAD_THEME 0
You can even disable themes only for certain URLs using SetEnvIf:
SetEnvIf Request_URI "^/api/" DJEBEL_APP_CORE_THEME_LOAD_THEME=0
That way your API routes skip the theme while your regular pages keep it.
This approach works really well for containerized setups or when you want different behavior per environment. Same codebase, different config.
Use @dj_if in app.ini
If you use the same app.ini across dev, staging, and production, you can conditionally set values based on environment variables right inside the config file:
[theme]
theme_id = djebel
load_theme = @dj_if env.DEV_ENV:0
The format is @dj_if env.VAR=value:RESULT. The env. namespace checks environment variables. If the condition matches, the value becomes the result. If it doesn't match, the value becomes an empty string.
You can match exact values, use wildcards, or check multiple values with a pipe:
; If APP_ENV equals "dev" → 0
load_theme = @dj_if env.APP_ENV=dev:0
; If APP_ENV starts with "dev" (matches dev, development) → 0
load_theme = @dj_if env.APP_ENV=dev*:0
; If APP_ENV contains "stag" → 0
load_theme = @dj_if env.APP_ENV=*stag*:0
; If APP_ENV is "dev" OR "staging" → 0
load_theme = @dj_if env.APP_ENV=dev|staging:0
This keeps one config file for all environments. No duplicates, no external scripts. The condition is evaluated when the INI file is parsed.
Use a Filter Hook
If you need more control, you can hook into app.core.theme.load_theme from a plugin:
Dj_App_Hooks::addFilter('app.core.theme.load_theme', [ $this, 'disableTheme', ]);
This lets you decide at runtime whether to load a theme or not, based on request type, URL, or whatever logic you need.
What Happens When There's No Theme
When Djebel sees that no theme is configured, here's what changes:
- The
themes.phpfile is never loaded - Theme hooks don't fire (no
app.core.theme.setup, noapp.core.theme.theme_loaded) - Instead,
app.core.theme.theme_not_loadedfires so your plugins know what's going on - The content hooks still fire normally:
app.page.content.render,app.page.content, andapp.page.full_content
Your plugins hook into app.page.content.render to output content directly. Other plugins can still filter that content through app.page.content and app.page.full_content just like they would on a themed site.
Everything still works. You just skip the theme part.
When Would You Use This?
Running without a theme makes sense when your site doesn't need one:
- API services that return JSON and never render HTML
- Headless backends where a frontend framework handles the UI
- Plugin-rendered single page applications
- Microservices that process data without visual output
- Webhook receivers and background workers
In all of these cases, loading a theme is unnecessary. Skipping it means faster responses and less memory usage.
Your Next Step
If you have a Djebel site that doesn't need a visual theme, try removing the [theme] section from your app.ini. You'll get a leaner startup with no theme overhead.
If your site serves both regular pages and API endpoints, the filter hook or the Apache SetEnvIf approach lets you disable themes only for the routes that don't need them. Your API gets faster while your public pages keep their look.
Less loaded, faster served.