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.php file is never loaded
  • Theme hooks don't fire (no app.core.theme.setup, no app.core.theme.theme_loaded)
  • Instead, app.core.theme.theme_not_loaded fires so your plugins know what's going on
  • The content hooks still fire normally: app.page.content.render, app.page.content, and app.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.