Installation:
composer require deepaspl/theme-bundle
Add to config/bundles.php:
return [
// ...
Liip\ThemeBundle\LiipThemeBundle::class => ['all' => true],
];
Basic Configuration (config/packages/liip_theme.yaml):
liip_theme:
themes: ['default', 'dark', 'corporate']
active_theme: 'default'
First Use Case:
src/YourBundle/Resources/themes/dark/
src/YourBundle/Resources/themes/dark/index.html.twig) alongside the default view./theme/switch?theme=dark (if routing is imported).Organize views by theme:
src/YourBundle/Resources/
├── themes/
│ ├── default/
│ │ ├── index.html.twig
│ │ └── partials/
│ └── dark/
│ ├── index.html.twig
│ └── partials/
└── views/ # Fallback if theme not found
<form action="{{ path('liip_theme_switch') }}" method="post">
<select name="theme">
{% for theme in themes %}
<option value="{{ theme }}">{{ theme|humanize }}</option>
{% endfor %}
</select>
<button type="submit">Switch</button>
</form>
$this->get('liip_theme')->setTheme('dark');
Override assets (CSS/JS) per theme:
src/YourBundle/Resources/public/themes/
├── default/
│ └── styles.css
└── dark/
└── styles.css
Reference in Twig:
<link rel="stylesheet" href="{{ asset('bundles/yourbundle/themes/' ~ activeTheme ~ '/styles.css') }}">
Access active theme in templates:
{% set activeTheme = app.request.attributes.get('_liip_theme') %}
{% if activeTheme == 'dark' %}
<body class="dark-theme">
{% endif %}
Use {% extends %} with fallback:
{% extends activeTheme ~ '/base.html.twig' if activeTheme != 'default' else 'base.html.twig' %}
Routing Conflicts:
/theme prefix doesn’t clash with existing routes. Use _liip_theme route name as a prefix:
liip_theme:
resource: "@LiipThemeBundle/Resources/config/routing.xml"
prefix: /_liip_theme
Caching Issues:
php bin/console cache:clear
Case Sensitivity:
strtolower() when validating:
$theme = strtolower($request->get('theme'));
Missing Fallback:
Resources/views/. Add validation:
liip_theme:
strict_theme_check: true # Throws exception if theme not found
Check Active Theme: Dump the active theme in a template:
{{ dump(app.request.attributes.get('_liip_theme')) }}
Verify Theme Paths:
Use Symfony’s asset() helper to debug paths:
{{ asset('bundles/yourbundle/themes/' ~ activeTheme ~ '/missing-file.css') }}
Logging: Enable debug mode to log theme switches:
liip_theme:
debug: true
Custom Theme Storage:
Override theme storage (e.g., database) by extending Liip\ThemeBundle\Storage\ThemeStorageInterface:
class DatabaseThemeStorage implements ThemeStorageInterface {
public function getActiveTheme() { /* ... */ }
public function setActiveTheme($theme) { /* ... */ }
}
Register as service:
services:
liip_theme.storage:
class: App\Service\DatabaseThemeStorage
Theme Events: Listen for theme changes via events:
$eventDispatcher->addListener(Liip\ThemeBundle\Event\ThemeEvent::THEME_CHANGED, function ($event) {
// Log or trigger actions on theme switch
});
Dynamic Theme Loading:
Load themes from external sources (e.g., S3) by implementing Liip\ThemeBundle\Loader\ThemeLoaderInterface.
$this->get('liip_theme')->preloadThemes(['default', 'dark']);
<link rel="stylesheet" href="{{ asset('bundles/yourbundle/themes/' ~ activeTheme ~ '/styles.css?v=' ~ activeTheme) }}">
How can I help you explore Laravel packages today?