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

integrated/theme-bundle

Integrated Theme Bundle provides theme management for PHP applications, letting you organize, configure, and switch between themes with integrated asset and template support. It helps keep theme files structured and apply consistent styling across your app.

View on GitHub
Deep Wiki
Context7

Getting Started

First, set expectations correctly. integrated/theme-bundle is a Symfony bundle, not a Laravel package. It ships no ServiceProvider, no facade, and no config/theme.php. It targets Symfony's DI container, EventDispatcher, and Twig loader. This means your "day one" as a Laravel developer is one of two paths: (a) run it inside a Symfony kernel, or (b) treat it as a reference implementation and port the ~200 lines of registry/resolver logic into your app. Do not attempt composer require and expect it to wire itself up.

Path A — Symfony install (if that is actually your stack):

composer require integrated/theme-bundle
// config/bundles.php
return [
    // ...
    Integrated\Bundle\ThemeBundle\IntegratedThemeBundle::class => ['all' => true],
];
# config/packages/integrated_theme.yaml
integrated_theme:
    themes:
        default:
            path: '%kernel.project_dir%/themes/default'
        acme:
            path: '%kernel.project_dir%/themes/acme'
    # host/domain -> theme mapping is the usual entry point

Where to look first, in this order:

  1. DependencyInjection/Configuration.php — the config tree is the public API. Read it before anything else.
  2. The theme registry / manager service — the object you inject into controllers to call setTheme() / getTheme().
  3. The kernel.request subscriber — this is where a theme gets chosen per request (host, locale, cookie, user).
  4. The compiler pass that registers Twig loader paths — this determines whether @theme/... templates resolve at all. When templates "aren't found," this is almost always why.

First use case to prove end-to-end: one codebase serving two hosts, each with its own template overrides and asset directory, falling back to a shared default theme for anything the site-specific theme does not override. Prove that before touching anything cleverer. If you cannot demonstrate a clean two-host swap with fallback on the first day, stop and reassess whether the abstraction pays its rent.

Laravel port sketch (Path B): if you are porting rather than installing, the equivalent surface is a ThemeManager singleton configured from config/theme.php, a middleware or Route::domain() binding that resolves the active theme before the controller runs, and a Blade view-path registration that prepends theme-specific paths ahead of resources/views. That is a couple hundred lines of idiomatic Laravel and is what the spike should produce.

Implementation Patterns

Runtime theme resolution per request. The package's model is: resolve a site/tenant context at request time, map it to a theme name, and hand that theme to the registry before views render. In practice this lives in a request subscriber (Symfony) or middleware (Laravel port). Keep it the only place a theme gets set. Scattered setTheme() calls across controllers are the most common cause of "wrong theme on one specific page."

Fallback-first template structure. Structure themes as themes/<name>/ with only the templates that actually differ from default, then fall back to default for everything else. This is what makes shared themes viable across sites. If you require every theme to redefine every layout, you will spend your days re-merging templates whenever a shared layout changes.

Asset resolution through the theme, not by convention. Theme assets (CSS, images, fonts) should resolve through the theme package's asset path, symlinked or published into public/. Do not let templates hardcode /assets/... paths, or the theme swap silently serves the wrong brand's logo. Keep a single theme_asset() helper (or Twig function) that produces the correct path.

Config-driven theme registry, not hardcoded names. Define themes in config (name, path, host mapping, labels) so that adding a fourth site is a config change plus a theme directory, not a code change. In a Laravel port this maps directly to config/theme.php returning ['themes' => [...], 'map' => ['acme.test' => 'acme'], 'default' => 'default'].

Testing pattern: assert the resolved theme per host. The single most valuable test in this category is a small data provider that hits each host and asserts that ThemeManager::current() returns the expected name and that a known overridden template renders the site-specific variant while a non-overridden template renders the default variant. This catches context bleed, fallback masking, and cache issues in one test.

Integration tip for brownfield apps: treat adoption as consolidation. Inventory the existing theming (view namespacing, config flags, per-tenant directories), map it against the package's registry model, and only migrate the parts where the package genuinely simplifies. Do not run two theme resolution mechanisms in parallel — whichever executes last wins, silently.

Multi-theme within one deployment: if a user can switch themes (e.g. preview mode, A/B campaign, dark/light as a theme), store the choice in a session or cookie and read it in the resolver before falling back to the host mapping. Just make preview state explicit and excluded from production resolution paths.

Gotchas and Tips

It is not a Laravel package. The -bundle suffix and the integratedfordevelopers vendor reflect Symfony lineage. Do not attempt to register it as a Laravel provider. A thin ServiceProvider wrapper around a Symfony-ported class is possible but is effectively a fork — pick that consciously and document it.

No upstream support, no compatibility pressure. One star, zero dependents. Assume you own any version you install. Verify PHP/Laravel (or Symfony) version constraints yourself, and treat every major framework upgrade as a scheduled patch exercise rather than "composer update and hope."

View caching and theme resolution interact badly if done naively. If theme selection reads the filesystem or hits a database on every request, it becomes a per-request tax multiplied by every page view. Memoize the resolved theme once per request. More importantly, if compiled views are cached under one theme and served under another, you get cross-tenant view bleed — the most customer-visible failure mode in this category. Test with the view cache warm and under load.

Config cache must be exercised. config:cache (Laravel) or cache:clear/cache:warmup (Symfony) can freeze theme paths at build time. If theme paths are computed at runtime (e.g. from request host), they will break under config cache. Keep config static, resolve per-request mapping separately.

Silent fallback to default masks configuration errors. A misconfigured host mapping that quietly falls back to the default theme looks like it works in staging and shows the wrong brand in production. Log loudly when an expected theme is not found, and consider failing closed in non-production environments.

Theme swap leaves stale assets. Publishing or symlinking theme assets is a separate step from activating the theme. After a swap you can end up with correct templates rendering against the wrong asset set. Tie asset publication into your deploy script and make it idempotent.

Octane and long-lived workers. Theme state held in a singleton that is not reset per request can leak between requests in an Octane/worker context. Ensure the manager is request-scoped via scoped() in Laravel or equivalent, or reset explicitly at the start of each request.

Extension points to know before you customize. The four places you will realistically touch are: the config tree (declaring themes and host mappings), the theme registry/manager service (adding methods like getAvailableThemes()), the request subscriber (changing how a theme is chosen), and the compiler pass / view-path registration (changing template lookup order). Document these four in your own README when you adopt — the source is the only documentation you are going to get.

Treat the source as the reference, not the dependency. For anything on a critical path, the working posture is: fork under MIT, own it internally, and keep a small test suite that asserts the two-host-with-fallback behavior. That test suite is what lets you upgrade Laravel/Symfony safely when the upstream repo does nothing.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings