Theme Hooks and Events
Botble CMS provides a powerful event system that allows you to customize your theme's behavior at various points in the rendering process. This documentation covers the available hooks and events in the theme system.
Introduction to Theme Events
Theme events are triggered at specific points during the theme rendering process, allowing you to modify the behavior or add functionality. These events are defined in your theme's config.php file.
Core Theme Events
before
Triggered before the theme is set up. This is useful for setting up global variables or configurations.
'before' => function (Theme $theme): void {
// Set up global variables or configurations
$theme->set('globalVariable', 'value');
},beforeRenderTheme
Triggered before rendering the theme. This is the ideal place to add assets, set up breadcrumbs, or prepare data for the theme.
'beforeRenderTheme' => function (Theme $theme): void {
// Add theme assets
$theme->asset()->usePath()->add('main-css', 'css/main.css');
$theme->asset()->container('footer')->usePath()->add('main-js', 'js/main.js');
// Set up breadcrumbs
$theme->breadcrumb()->add('Home', route('public.index'));
// Set global variables
$theme->set('categories', get_categories());
},beforeRenderLayout
Triggered before rendering a specific layout. This allows you to add layout-specific assets or configurations.
'beforeRenderLayout' => [
'default' => function (Theme $theme): void {
// Add assets specific to the default layout
$theme->asset()->usePath()->add('default-layout-css', 'css/layouts/default.css');
},
'blog' => function (Theme $theme): void {
// Add assets specific to the blog layout
$theme->asset()->usePath()->add('blog-layout-css', 'css/layouts/blog.css');
},
],after
Triggered after the theme has been set up but before it's rendered. This is useful for final adjustments.
'after' => function (Theme $theme): void {
// Make final adjustments before rendering
},Custom Events
You can also create and trigger custom events in your theme. This is useful for creating modular, event-driven themes.
Creating a Custom Event
// In your theme's functions/functions.php
app()->booted(function (): void {
add_action('theme_custom_event', function ($param) {
// Handle the custom event
echo "Custom event triggered with: " . $param;
});
});Triggering a Custom Event
// Trigger the custom event
do_action('theme_custom_event', 'parameter');Laravel Event Classes
Botble CMS dispatches Laravel event classes at key points in the theme lifecycle. You can listen to these in your theme's functions/functions.php or in a plugin's service provider.
RenderingThemeOptionSettings
Fired when the theme options settings page is rendered in admin. This is where you register theme option fields.
use Botble\Theme\Events\RenderingThemeOptionSettings;
app('events')->listen(RenderingThemeOptionSettings::class, function (): void {
theme_option()
->setField([
'id' => 'my_option',
'section_id' => 'opt-text-subsection-general',
'type' => 'text',
'label' => __('My Option'),
'attributes' => [
'name' => 'my_option',
'value' => null,
],
]);
});RenderingTheme
Fired during global asset rendering (via fireEventGlobalAssets()). Use this to add assets that should be loaded on every page.
use Botble\Theme\Events\RenderingTheme;
app('events')->listen(RenderingTheme::class, function (): void {
Theme::asset()->usePath()->add('custom-css', 'css/custom.css');
});RenderingHomePageEvent
Fired when the homepage is being rendered. Use this to load homepage-specific data or assets.
use Botble\Theme\Events\RenderingHomePageEvent;
app('events')->listen(RenderingHomePageEvent::class, function (): void {
// Load homepage-specific data
});RenderingSingleEvent
Fired when a single content page is rendered (post, page, etc.). The event carries the Slug model.
use Botble\Theme\Events\RenderingSingleEvent;
app('events')->listen(RenderingSingleEvent::class, function (RenderingSingleEvent $event): void {
$slug = $event->slug;
// Customize rendering for this specific content
});RenderingSiteMapEvent
Fired when generating the sitemap. Optionally carries a key to identify the sitemap section.
use Botble\Theme\Events\RenderingSiteMapEvent;
app('events')->listen(RenderingSiteMapEvent::class, function (RenderingSiteMapEvent $event): void {
$key = $event->key; // null for main sitemap, or a specific section key
// Add custom URLs to sitemap
});RenderingAdminBar
Fired when the frontend admin bar is being rendered. Use this to add custom links.
use Botble\Theme\Events\RenderingAdminBar;
app('events')->listen(RenderingAdminBar::class, function (): void {
admin_bar()
->registerLink('Custom Link', route('my.route'), 'add-new', 'my.permission');
});ThemeRoutingBeforeEvent / ThemeRoutingAfterEvent
Fired before and after theme routes are registered. The event carries the Router instance.
use Botble\Theme\Events\ThemeRoutingBeforeEvent;
use Botble\Theme\Events\ThemeRoutingAfterEvent;
app('events')->listen(ThemeRoutingBeforeEvent::class, function (ThemeRoutingBeforeEvent $event): void {
$router = $event->router;
// Modify routing before theme routes load
});
app('events')->listen(ThemeRoutingAfterEvent::class, function (ThemeRoutingAfterEvent $event): void {
$router = $event->router;
// Add routes after theme routes are loaded
});ThemeRemoveEvent
Fired when a theme is removed via the cms:theme:remove command. Carries the theme name.
use Botble\Theme\Events\ThemeRemoveEvent;
app('events')->listen(ThemeRemoveEvent::class, function (ThemeRemoveEvent $event): void {
$themeName = $event->theme;
// Clean up theme-specific data
});Event Lifecycle Order
The following shows the order events fire during a typical page request:
1. ThemeRoutingBeforeEvent → Before routes are registered
2. ThemeRoutingAfterEvent → After routes are registered
3. before (config.php) → Theme setup begins
4. beforeRenderTheme → Before theme renders (add assets here)
5. RenderingTheme → Global asset event
6. beforeRenderLayout → Before specific layout renders
7. RenderingHomePageEvent → (Homepage only)
8. RenderingSingleEvent → (Single content pages only)
9. after (config.php) → Final adjustments
10. RenderingAdminBar → Admin bar renders (logged-in admins)Theme Filters
Filters allow you to modify data at specific points in the theme rendering process.
BASE_FILTER_THEME_HEADER
This filter allows you to modify the theme header content:
add_filter(BASE_FILTER_THEME_HEADER, function ($header) {
// Modify the header content
return $header . '<meta name="custom-meta" content="value">';
}, 120);BASE_FILTER_THEME_FOOTER
This filter allows you to modify the theme footer content:
add_filter(BASE_FILTER_THEME_FOOTER, function ($footer) {
// Modify the footer content
return $footer . '<script>console.log("Custom footer script");</script>';
}, 120);BASE_FILTER_GROUP_PUBLIC_ROUTE
This filter allows you to modify the public route group attributes:
add_filter(BASE_FILTER_GROUP_PUBLIC_ROUTE, function ($attributes) {
// Add middleware to all public routes
$attributes['middleware'][] = 'custom.middleware';
return $attributes;
}, 120);Practical Examples
Adding Google Analytics
// In your theme's config.php
'beforeRenderTheme' => function (Theme $theme): void {
// Add Google Analytics script to the footer
$googleAnalyticsId = theme_option('google_analytics_id');
if ($googleAnalyticsId) {
$theme->asset()->container('footer')->writeScript('google-analytics', '
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=' . $googleAnalyticsId . '"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag("js", new Date());
gtag("config", "' . $googleAnalyticsId . '");
</script>
<!-- End Google Analytics -->
');
}
},Adding Custom CSS for Specific Pages
// In your theme's functions/functions.php
app()->booted(function (): void {
add_action('theme_header', function () {
// Check if current page is the contact page
if (Route::currentRouteName() == 'public.contact' || request()->segment(1) == 'contact') {
echo '<style>
.contact-form { background-color: #f5f5f5; padding: 20px; border-radius: 5px; }
.contact-form input, .contact-form textarea { width: 100%; margin-bottom: 10px; }
</style>';
}
});
});Checking Current Page Type
Here are different ways to check the current page type in Botble CMS:
// Check if current page is a blog post
if (in_array(Route::currentRouteName(), ['public.single', 'public.post']) && $post = get_object_instance()) {
// This is a blog post page
}
// Check if current page is a category page
if (Route::currentRouteName() == 'public.category' && $category = get_object_instance()) {
// This is a category page
}
// Check if current page is the homepage
if (Route::currentRouteName() == 'public.index') {
// This is the homepage
}
// Check by URL segment
if (request()->segment(1) == 'products') {
// URL contains /products
}Modifying the Breadcrumb
// In your theme's functions/functions.php
app()->booted(function (): void {
add_filter('theme_breadcrumb_template', function ($template) {
// Return a custom breadcrumb template
return '<nav aria-label="breadcrumb">
<ol class="breadcrumb custom-breadcrumb">
{!! $crumbs !!}
</ol>
</nav>';
});
});Best Practices
- Keep event handlers focused: Each event handler should have a single responsibility.
- Use appropriate events: Choose the right event for your needs to ensure your code runs at the correct time.
- Consider performance: Heavy operations in event handlers can slow down your site. Use caching when appropriate.
- Organize your code: Keep related event handlers together in your theme's files.
- Document your events: If you create custom events, document them for future reference.
