Using Hooks
categoryHow To
edit_calendar31 Mar 2026
How to Use Hooks
Hooks are the primary extension mechanism in GeniXCMS. They allow themes and modules to add functionality or modify output without editing core files.
There are two types of hooks:
- Actions — Execute a function at a specific point (no return value expected).
- Filters — Modify a value and return the modified result.
Actions
Attaching an Action
Usage: Hooks::attach(string $hook_name, callable $callback, int $priority = 10);
// Attach a function to the 'footer_load_lib' hook
Hooks::attach('footer_load_lib', ['MyTheme', 'loadAssets']);
// Or with a closure
Hooks::attach('post_submit_add_action', function($data) {
// Send a notification email when a post is added
Mail::send([
'to' => '[email protected]',
'subject' => 'New Post Published',
'message' => 'A new post was just published.',
]);
});
Running an Action
Usage: Hooks::run(string $hook_name, mixed $data = '');
// In a theme template (Latte)
{Hooks::run('footer_load_lib')|noescape}
// In PHP code
Hooks::run('post_submit_add_action', $_POST);
Filters
Attaching a Filter
Usage: Hooks::filter(string $hook_name, mixed $value);
The attached function must accept the value and return a (modified) value.
// Attach a filter to modify post titles
Hooks::attach('post_title_filter', function($title) {
return strtoupper($title); // uppercase all titles
});
Applying a Filter
// In PHP
$title = Hooks::filter('post_title_filter', $post->title);
// In a Latte template
{Hooks::filter('post_title_filter', $post->title)|noescape}
Common System Hooks
Action Hooks
| Hook | Trigger Point | $data Type |
|---|---|---|
footer_load_lib |
Just before </body> in every page |
(none) |
header_load_meta |
Inside <head> of every page |
(none) |
init |
Standard system startup finished | (none) |
post_submit_add_action |
After a new post is saved | $_POST array |
post_sqldel_action |
After a post is deleted from database | int $id |
admin_sidebar_start |
Before the first admin sidebar menu | (none) |
admin_sidebar_end |
After the last admin sidebar menu | (none) |
theme_activated_action |
After a theme is successfully activated | string $theme_name |
admin_page_dashboard_action |
On the admin dashboard | $data array |
admin_footer_action |
At the bottom of every admin page | (none) |
user_login_action |
After a successful user login | $data array |
user_register_action |
After a new user registers | $data array |
post_param_form_bottom |
At the bottom of the main post form area | $data array |
post_param_form_sidebar |
At the bottom of the post form sidebar | $data array |
page_param_form_bottom |
At the bottom of the main page form area | $data array |
page_param_form_sidebar |
At the bottom of the page form sidebar | $data array |
Filter Hooks
| Hook | What It Filters |
|---|---|
post_title_filter |
Post title string before display |
post_pre_insert_filter |
Modify entire post data before inserting to DB |
post_pre_update_filter |
Modify entire post data before updating in DB |
user_pre_insert_filter |
Modify entire user data before creating user |
user_pre_update_filter |
Modify entire user data before updating |
post_submit_title_filter |
Title string during save (sanitize) |
post_submit_content_filter |
Content string during save (sanitize) |
post_content_filter |
Post body HTML before render |
system_security_headers_args |
CSP rules array (directives and sources) |
search_type_filter |
Array of post types to include in Search queries |
breadcrumbs_filter |
Array of breadcrumb items (label and URL) |
post_url |
Array containing the generated URL and post ID |
widget_locations |
Associative array of available widget zones/locations |
editor_type_options |
Associative array of available editor engines |
Priority
Attach multiple callbacks to the same hook. Lower priority numbers run first.
Hooks::attach('footer_load_lib', ['Analytics', 'load'], 5); // runs first
Hooks::attach('footer_load_lib', ['Ads', 'load'], 20); // runs later
Registering Hooks in a Theme
For a modern theme implementation, put all hook registrations inside a dedicated Theme Class within your function.php. This approach keeps your code organized and allows for clean access to theme utilities like the Asset manager.
<?php
class MyModernTheme
{
public function __construct()
{
// 1. Efficiently load assets (Alternative to footer_load_lib echo)
$this->setupAssets();
// 2. Attach filters (Title & Content)
Hooks::attach('post_title_filter', [self::class, 'injectTitleIcon'], 10);
Hooks::attach('post_content_filter', [self::class, 'formatContent'], 20);
// 3. Register Widget zones specifically for this theme
Widget::addLocation('sidebar_landing', 'Landing Page Sidebar');
}
private function setupAssets()
{
// Load default Bootstrap from CDN
Asset::enqueue(['bootstrap-css', 'bootstrap-js', 'bootstrap-icons']);
// Register theme-specific JS/CSS
Asset::register('theme-css', 'css', Url::theme() . '/css/style.css', 'header');
Asset::register('theme-js', 'js', Url::theme() . '/js/app.js', 'footer', ['jquery']);
Asset::enqueue(['theme-css', 'theme-js']);
}
public static function injectTitleIcon($title)
{
// Add a book icon to every post title
return '📖 ' . $title;
}
public static function formatContent($content)
{
// Automatically add a "Related Posts" section after content
$related = '<hr><p class="fw-bold">Don\'t forget to share this post!</p>';
return $content . $related;
}
}
new MyModernTheme();
See Also
HooksClass API — Full method reference.- Create a Theme — Where to register hooks in a theme.
- Create a Module — Using hooks in modules.