Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Theme Bundle Laravel Package

jungi/theme-bundle

JungiThemeBundle adds flexible theme management to Symfony/PHP applications, letting you define multiple themes, use inheritance, override templates and assets, and select the active theme through configuration or custom resolvers.

View on GitHub
Deep Wiki
Context7

Getting Started

Check the Symfony version first. v1.0.1 added Symfony 3 support, so the bundle now runs on Symfony 2.x and 3.x (still PHP 5.x/7.0-era Twig, still no Symfony 4+ or Twig 2+). If the project is on Symfony 4 or later, stop here — you will spend more time shimming the DI container and Twig loader than the theming is worth. For a greenfield app, use Twig namespaced paths (@theme_default/...) or liip/theme-bundle instead; the concepts map almost 1:1.

Minimal steps for a legacy Symfony 2/3 app:

  1. Require it (jungi/theme-bundle) at ^1.0.1 — earlier tags predate Symfony 3 support — and register new Jungi\Bundle\ThemeBundle\JungiThemeBundle() in AppKernel.
  2. Look first at Resources/doc/ in the repository, then at DependencyInjection/Configuration.php. The docs are from 2015 and drift from the code; the configuration tree is the authoritative source for exact key names.
  3. Declare the smallest possible config: a jungi_theme.themes map with one default theme pointing at your existing views directory, and set default_theme: default. Confirm nothing breaks — the bundle should be transparent at this point.
  4. Add a second theme (e.g. xmas) whose path(s) contain only the templates you actually want to override.

First real use case: override a single template for a seasonal/white-label skin without duplicating controllers. Put the overriding file at the same relative path inside the second theme's directory, switch the current theme, and let the bundle's loader prefer the theme file while falling back to the bundle's original. If that fallback doesn't happen, your theme paths are wrong, not your templates.

Implementation Patterns

Switch the current theme via the manager, not by hand-editing config. Inject jungi_theme.theme_manager and call setCurrentTheme('xmas') early in the request (a kernel.request listener is the right place). Read back with getCurrentTheme(). Keep the "which theme" decision in exactly one listener so controllers and subrequests stay consistent.

Prefer automatic resolution over manual switching. The bundle ships theme resolvers (rule-based, and a device-oriented one if the companion device bundle is installed). Configure a rule resolver so a cookie/session/query parameter selects the theme, and fall back to default_theme. This is the pattern you actually want day-to-day: one config block, zero controller code.

Write a custom resolver when rules aren't enough. Implement the bundle's theme-resolver interface as a service and tag it (check Resources/config/*.xml for the exact tag name). Keep it side-effect free and cheap — it runs on every request. Typical cases: resolve by hostname for multi-tenant, by authenticated user's preference, by A/B bucket.

Render through the template manager for engine-agnostic code. The bundle exposes a template-manager service implementing render($name, $params) and renderResponse($name, $params, Response $response = null). Using this in controllers means the theme lookup happens once, in one place, rather than relying on every template include being theme-aware. For Twig-only apps, the theme-aware Twig loader is enough.

Structure themes as a thin overlay, not a fork. A theme directory should contain only the files that differ. Rely on parent/fallback so the 90% of templates that don't change stay in one place. This is the single biggest maintainability lever with this bundle.

Persist the choice outside the request. Store the selected theme in the session or a cookie in the same listener that calls setCurrentTheme, so the next request resolves identically. Without this, theme selection resets to default_theme on every page load.

Test it explicitly. In functional tests, set the theme in setUp and assert on rendered output or on getCurrentTheme(). Also add one test that runs with the default theme to catch accidental coupling.

Gotchas and Tips

  • Effectively unmaintained, even though Symfony 3 landed. v1.0.1 is a single-line compatibility bump, not a revival — there are still no security fixes and no Symfony 4+/Twig 2+ work on the horizon. Pin exact versions in composer.json, and plan to fork rather than wait for upstream. If you fork, add a vcs repository entry and keep the namespace.
  • Do not assume the Symfony 3 bump is clean. The release notes only say "Enabled support for the Symfony3." — treat the DI definitions, Twig loader wiring, and any ContainerAware/deprecated API calls as unverified until you exercise them. Smoke-test bundle registration and template resolution on the exact Symfony 3 minor you run; a 2016-era bundle on Symfony 3.4 is not the same as on 3.0.
  • Current theme is request-scoped global state. In CLI commands, queue workers, and long-running processes it silently stays at whatever was set last — always set it explicitly at the start of a command. In tests, reset it in tearDown or you'll get order-dependent failures.
  • Subrequests and ESI don't inherit your listener's work. A fragment rendered in a subrequest may resolve a different theme. Set the theme from a listener that runs for subrequests too, or pass it explicitly into fragments.
  • Cache invalidation is the #1 debugging trap. Template locations and resolver results get cached (Twig cache and/or container). After adding a theme path — and especially after the Symfony 3 upgrade rearranges container compilation — clear the cache before concluding the config is wrong. In dev, verify with debug:container | grep jungi_theme that your service and tag are actually registered.
  • Path precedence is order-sensitive. When two themes expose the same template, whichever path is registered first wins. Override lists deliberately; don't rely on filesystem ordering.
  • Config schema drift. Old blog posts and even the repo docs may show keys that no longer match Configuration.php. When in doubt, read the config tree and let config:dump-reference jungi_theme (if available on your Symfony version) tell you the truth.
  • Resolver ordering matters. Resolvers are consulted in tag/priority order; a rule resolver that always returns a theme will shadow the device resolver. Make each resolver return "no decision" rather than a default, and let default_theme be the single fallback.
  • Debugging the resolved theme. Dump getCurrentTheme() and the theme's resource paths from a throwaway controller or a kernel.request listener. Most "wrong template" reports are actually "theme resolved to default" — check the theme before checking the template.
  • Extension points worth knowing: custom theme classes, custom theme resolvers (tagged services), and decorating the template locator. Avoid patching the bundle in vendor/; a decorator on the locator covers most override needs.
  • Migration path out. If you're planning to leave Symfony 2/3, the exit is mechanical: convert each theme to a Twig namespace (@theme_mobile/...), replace setCurrentTheme calls with a request attribute, and delete the bundle. Do it incrementally, one theme at a time, using the fallback behaviour to keep both systems rendering the same output.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource