contao-thememanager/ctm-base-bundle
Installation
composer require contao-thememanager/ctm-base-bundle
Ensure ContaoManagerBundle is installed (required dependency).
Enable the Bundle
Add to config/bundles.php:
ContaoThememanager\CtmBaseBundle\ContaoThememanagerCtmBaseBundle::class => ['all' => true],
First Use Case: Basic Theme Integration
themes/ (e.g., themes/my_custom_theme/).theme.xml file in the root of your theme:
<theme name="My Custom Theme" icon="bundles/contao-thememanagerctmbase/images/icon.svg">
<template>default</template>
</theme>
config/packages/contao_thememanager.yaml:
contao_thememanager:
themes:
my_custom_theme:
path: '%kernel.project_dir%/themes/my_custom_theme'
Verify Installation
php bin/console cache:clear./contao) and navigate to System > Themes to see your theme listed.Template Inheritance:
Extend base templates by overriding files in your theme’s templates/ directory. Use {% extends 'base.html.twig' %} in Twig templates.
Example:
{# themes/my_custom_theme/templates/page.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}{{ page.title }} - Customized{% endblock %}
Asset Management:
Override CSS/JS by placing files in themes/my_custom_theme/assets/ and reference them in theme.xml:
<assets>
<css>css/style.css</css>
<js>js/custom.js</js>
</assets>
CtmThemeManager service to switch themes programmatically:
use ContaoThememanager\CtmBaseBundle\Service\CtmThemeManager;
public function __construct(private CtmThemeManager $themeManager) {}
public function changeTheme(string $themeName): void
{
$this->themeManager->setActiveTheme($themeName);
}
tl_theme table or custom fields.tl_theme for a "dark mode" toggle:
// In a custom DataContainer
$dc->fields['dark_mode'] = [
'label' => ['tl_theme', 'dark_mode'],
'inputType' => 'checkbox',
'eval' => ['tl_class' => 'w50'],
];
ctm.theme.switch event to run logic when themes change:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use ContaoThememanager\CtmBaseBundle\Event\ThemeSwitchEvent;
class ThemeSwitchSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'ctm.theme.switch' => 'onThemeSwitch',
];
}
public function onThemeSwitch(ThemeSwitchEvent $event): void
{
// Log or perform actions when theme changes
\Contao\System::log('Theme switched to: ' . $event->getThemeName(), __METHOD__, TL_GENERAL);
}
}
%kernel.environment% to load environment-specific themes:
# config/packages/contao_thememanager.yaml
contao_thememanager:
themes:
dev_theme:
path: '%kernel.project_dir%/themes/dev'
environments: [dev]
prod_theme:
path: '%kernel.project_dir%/themes/prod'
environments: [prod]
theme.xml:
<theme name="Child Theme" extends="parent_theme">
<template>child_template</template>
</theme>
use ContaoThememanager\CtmBaseBundle\Provider\ThemeProviderInterface;
class S3ThemeProvider implements ThemeProviderInterface
{
public function getThemes(): array
{
// Fetch themes from S3 and return as array
return [
's3_theme' => [
'path' => '/path/to/s3/theme',
'name' => 'S3 Theme',
],
];
}
}
services.yaml:
services:
App\Service\S3ThemeProvider:
tags: ['contao_thememanager.theme_provider']
Cache Invalidation
php bin/console cache:clear --env=prod
ctm:theme:clear-cache command for theme-specific cache:
php bin/console ctm:theme:clear-cache
Template Override Conflicts
themes/ directory.extends syntax in Twig templates.Missing theme.xml
theme.xml file. Omitting it will cause the theme to be ignored.Database Schema Mismatches
tl_theme, ensure your custom fields are added via a database update:
php bin/console contao:install:update
Symfony vs. Contao Routing Conflicts
# config/routes.yaml
contao:
resource: "@ContaoCoreBundle/Resources/config/routing.xml"
type: xml
prefix: /contao
Enable Debug Mode
Set APP_DEBUG=1 in .env to see detailed errors in the Contao backend.
Log Theme Events
Enable event logging in config/packages/contao_thememanager.yaml:
contao_thememanager:
debug: true
Check Active Theme
Use the CtmThemeManager service to debug the current theme:
$activeTheme = $this->themeManager->getActiveTheme();
\Contao\System::log('Active theme: ' . $activeTheme, __METHOD__, TL_GENERAL);
Template Debugging
Use Twig’s {% debug %} tag in templates to inspect variables:
{% debug theme %}
Custom Theme Validators
Extend theme validation logic by implementing ThemeValidatorInterface:
use ContaoThememanager\CtmBaseBundle\Validator\ThemeValidatorInterface;
class CustomThemeValidator implements ThemeValidatorInterface
{
public function validate(array $themeConfig): bool
{
// Custom validation logic
return true;
}
}
Register the validator in services.yaml:
services:
App\Validator\CustomThemeValidator:
tags: ['contao_thememanager.theme_validator']
Theme-Specific DCA Extensions Dynamically extend DataContainer fields based on the active theme:
use Contao\BackendTemplate;
use Contao\DataContainer;
$GLOBALS['TL_DCA']['tl_content']['fields']['custom_field'] = [
'label' => ['tl_content', 'custom_field'],
'inputType' => 'text',
'eval' => ['tl_class' => 'clr'],
'exclude' => true,
];
// Show only for specific themes
if (\Contao\System::getContainer()->get('contao_thememanager.theme_manager')->getActiveTheme() === 'my_theme') {
$GLOBALS['TL_DCA']['tl_content']['fields']['custom_field']['exclude'] = false;
}
**Hooks for Theme
How can I help you explore Laravel packages today?