Output Hooks Reference
Output hooks allow you to inject custom HTML, CSS, JavaScript, and other content into specific locations within the Mumara Campaigns interface. Unlike module hooks that respond to events, output hooks render content when pages are displayed.
How Output Hooks Work
Output hooks return content that gets concatenated and rendered at specific locations:
add_hook('HeadTop', 1, function($vars) {
return '<link rel="stylesheet" href="/my-styles.css">';
});
To retrieve the combined output from all callbacks registered to an output hook:
// In a Blade template
{!! hook_get_output('HeadTop', $vars) !!}
Available Context Variables
Output hooks receive a $vars array containing useful context:
add_hook('HeadTop', 1, function($vars) {
// Common variables available:
// $vars['route'] - Current route name
// $vars['user'] - Authenticated user object
// $vars['request'] - Current request object
return '<meta name="page" content="' . ($vars['route'] ?? 'unknown') . '">';
});
Document Head Hooks
HeadTop
Renders at the very top of the <head> section, before any other elements.
add_hook('HeadTop', 1, function($vars) {
return '<meta charset="UTF-8">';
});
Best For:
- Character encoding declarations
- Early meta tags
- Preconnect/preload hints
Example - Add Preconnect for External Resources:
add_hook('HeadTop', 1, function($vars) {
return <<<HTML
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
HTML;
});
HeadEnd
Renders at the end of the <head> section, just before the closing </head> tag.
add_hook('HeadEnd', 1, function($vars) {
return '<link rel="stylesheet" href="/custom/theme.css">';
});
Best For:
- Custom stylesheets
- Additional meta tags
- Favicon overrides
- Third-party CSS libraries
Example - Load Custom CSS Based on Route:
add_hook('HeadEnd', 1, function($vars) {
$route = $vars['route'] ?? '';
$css = '';
if (str_starts_with($route, 'campaigns.')) {
$css .= '<link rel="stylesheet" href="/css/campaigns-custom.css">';
}
if (str_starts_with($route, 'contacts.')) {
$css .= '<link rel="stylesheet" href="/css/contacts-custom.css">';
}
return $css;
});
Document Body Hooks
BodyTop
Renders immediately after the opening <body> tag.
add_hook('BodyTop', 1, function($vars) {
return '<div id="page-loader" class="loading"></div>';
});
Best For:
- Loading indicators
- No-JavaScript fallbacks
- Body-level wrapper elements
- Skip navigation links (accessibility)
Example - Add Accessibility Skip Link:
add_hook('BodyTop', 1, function($vars) {
return '<a href="#main-content" class="skip-link">Skip to main content</a>';
});
BodyEnd
Renders just before the closing </body> tag.
add_hook('BodyEnd', 1, function($vars) {
return '<script src="/custom/app.js"></script>';
});
Best For:
- JavaScript files
- Analytics scripts
- Chat widgets
- Deferred scripts
Example - Add Google Analytics:
add_hook('BodyEnd', 1, function($vars) {
$trackingId = config('services.google.analytics_id');
if (!$trackingId) {
return '';
}
return <<<HTML
<script async src="https://www.googletagmanager.com/gtag/js?id={$trackingId}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{$trackingId}');
</script>
HTML;
});
Navigation Hooks
PrimaryMenu
Allows adding items to the primary sidebar navigation menu.
add_hook('PrimaryMenu', 1, function($vars) {
return '<li class="nav-item"><a href="/custom-page" class="nav-link">Custom Page</a></li>';
});
Best For:
- Adding custom menu items
- Injecting addon navigation
- User-specific menu options
Example - Add Conditional Menu Item:
add_hook('PrimaryMenu', 1, function($vars) {
$user = $vars['user'] ?? null;
if (!$user || !$user->hasPermission('view_reports')) {
return '';
}
return <<<HTML
<li class="kt-menu__item">
<a href="/custom-reports" class="kt-menu__link">
<span class="kt-menu__link-icon">
<i class="fas fa-chart-bar"></i>
</span>
<span class="kt-menu__link-text">Custom Reports</span>
</a>
</li>
HTML;
});
TopNav
Renders content in the top navigation bar area.
add_hook('TopNav', 1, function($vars) {
return '<div class="top-nav-item">Custom Element</div>';
});
Best For:
- Custom top bar elements
- Quick action buttons
- Status indicators
BreadcrumbNav
Allows customization of breadcrumb navigation.
add_hook('BreadcrumbNav', 1, function($vars) {
$route = $vars['route'] ?? '';
if ($route === 'list.index') {
return <<<HTML
<div class="kt-subheader__breadcrumbs">
<a href="/dashboard" class="kt-subheader__breadcrumbs-link">Dashboard</a>
<span class="kt-subheader__breadcrumbs-separator"></span>
<span class="kt-subheader__desc">Contact Lists</span>
</div>
HTML;
}
return '';
});
Best For:
- Custom breadcrumb structures
- Dynamic breadcrumb content
- Route-specific navigation
Page Section Hooks
alerts
Renders alert messages in the main content area.
add_hook('alerts', 1, function($vars) {
return '<div class="alert alert-info">System update available.</div>';
});
Best For:
- System-wide alerts
- Warning messages
- Transactional limit notifications
Example - Show Sending Limit Warning:
add_hook('alerts', 1, function($vars) {
$user = auth()->user();
if (!$user) {
return '';
}
$dailyLimit = $user->daily_limit ?? 10000;
$sentToday = \App\Models\CampaignScheduleLog::where('user_id', $user->id)
->whereDate('created_at', today())
->count();
if ($sentToday < $dailyLimit * 0.8) {
return '';
}
$remaining = $dailyLimit - $sentToday;
return <<<HTML
<div class="alert alert-warning">
<strong>Sending Limit:</strong> You have {$remaining} emails remaining for today.
</div>
HTML;
});
AlertBar
Renders alert messages at the top of the page content area, below the navbar.
add_hook('AlertBar', 1, function($vars) {
return '<div class="alert alert-info">System maintenance scheduled for tonight.</div>';
});
Best For:
- System announcements
- Maintenance notices
- Feature announcements
Example - Show Maintenance Warning:
add_hook('AlertBar', 1, function($vars) {
$maintenanceTime = config('app.maintenance_scheduled');
if (!$maintenanceTime) {
return '';
}
$timeFormatted = \Carbon\Carbon::parse($maintenanceTime)->format('M j, Y g:i A');
return <<<HTML
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<strong>Scheduled Maintenance:</strong> The system will be briefly unavailable on {$timeFormatted}.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
HTML;
});
TitleBar
Renders in the page title bar area, typically for adding descriptions or badges.
add_hook('TitleBar', 1, function($vars) {
$route = $vars['route'] ?? '';
if ($route === 'list.index') {
return <<<HTML
<div class="pagetitle">
<h4>Contact Lists</h4>
<p>Manage your contact lists, import contacts, and organize your audience.</p>
</div>
HTML;
}
return '';
});
Best For:
- Page descriptions
- Status badges
- Quick action buttons
ContentEnd
Renders at the end of the main content area, before the footer.
add_hook('ContentEnd', 1, function($vars) {
return '<div class="content-footer">Additional content here</div>';
});
Best For:
- Related content sections
- Call-to-action blocks
- Content footers
Footer
Renders in the page footer section.
add_hook('Footer', 1, function($vars) {
return '<p>Custom footer content</p>';
});
Best For:
- Copyright notices
- Footer links
- Support information
- Version numbers
Example - Add Version Info to Footer:
add_hook('Footer', 10, function($vars) {
$version = config('app.version', '1.0.0');
return <<<HTML
<div class="footer-version text-muted">
<small>Version {$version}</small>
</div>
HTML;
});
Page-Specific Hooks
addPageHtml
A versatile hook for adding content to specific pages. Often used with route checking.
add_hook('addPageHtml', 1, function($vars) {
$route = $vars['route'] ?? '';
// Only add content on the dashboard
if ($route !== 'dashboard') {
return '';
}
return '<div class="dashboard-widget">Custom Widget</div>';
});
Example - Add Help Widget to Specific Pages:
add_hook('addPageHtml', 5, function($vars) {
$route = $vars['route'] ?? '';
$helpContent = [
'campaigns.create' => 'Need help creating a campaign? Check our guide.',
'contacts.import' => 'Importing contacts? Make sure your CSV is properly formatted.',
'settings.smtp' => 'Configure your SMTP settings for optimal deliverability.',
];
if (!isset($helpContent[$route])) {
return '';
}
$message = $helpContent[$route];
return <<<HTML
<div class="help-tip alert alert-light">
<i class="fas fa-lightbulb text-warning"></i> {$message}
<a href="/docs" target="_blank">Learn more</a>
</div>
HTML;
});
SocialLogin
Renders social login buttons on the login page.
add_hook('SocialLogin', 1, function($vars) {
return <<<HTML
<div class="social-login">
<a href="/auth/google" class="btn btn-google">
<i class="fab fa-google"></i> Sign in with Google
</a>
<a href="/auth/facebook" class="btn btn-facebook">
<i class="fab fa-facebook"></i> Sign in with Facebook
</a>
</div>
HTML;
});
Best For:
- OAuth login buttons
- Single Sign-On integration
- Third-party authentication
Automation & Campaign Hooks
AutomationAddBlankJS
Injects JavaScript for the automation add blank page.
add_hook('AutomationAddBlankJS', 1, function($vars) {
return '<script>console.log("Automation page loaded");</script>';
});
AutomationChooseTemplateJS
Injects JavaScript for the template selection page.
add_hook('AutomationChooseTemplateJS', 1, function($vars) {
return '<script>// Custom template selection logic</script>';
});
AutomationCreateBroadcast
Renders content in the broadcast creation form.
add_hook('AutomationCreateBroadcast', 1, function($vars) {
return '<div class="custom-broadcast-options">Custom options</div>';
});
AutomationCreateBroadcastButtons
Adds custom buttons to the broadcast creation form.
add_hook('AutomationCreateBroadcastButtons', 1, function($vars) {
return '<button type="button" class="btn btn-secondary">Custom Action</button>';
});
AutomationPackageSettings
Renders custom package settings in the package creation form.
add_hook('AutomationPackageSettings', 1, function($vars) {
return <<<HTML
<div class="form-group">
<label>Custom Package Setting</label>
<input type="text" name="custom_setting" class="form-control">
</div>
HTML;
});
AutomationUserSettingsTab
Adds a custom tab to user settings.
add_hook('AutomationUserSettingsTab', 1, function($vars) {
return '<li class="nav-item"><a class="nav-link" data-toggle="tab" href="#custom-tab">Custom</a></li>';
});
AutomationUserSettings
Renders content in the user settings custom tab.
add_hook('AutomationUserSettings', 1, function($vars) {
return '<div class="tab-pane" id="custom-tab">Custom settings content</div>';
});
Domain & SMTP Hooks
SendingDomainPageTitleBar
Renders content in the sending domain page title bar.
add_hook('SendingDomainPageTitleBar', 1, function($vars) {
return '<span class="badge badge-info">Custom Badge</span>';
});
btn_sync_now
Renders a sync button on domain pages.
add_hook('btn_sync_now', 1, function($vars) {
return '<button class="btn btn-primary" onclick="syncDomain()">Sync Now</button>';
});
NodesListingPageOutput
Returns custom output for the SMTP nodes listing page.
add_hook('NodesListingPageOutput', 1, function($vars) {
// $vars contains nodes listing data
return '<div class="custom-nodes-content">Custom nodes view</div>';
});
sendingDomainEditPageOutput
Returns custom output for the sending domain edit page.
add_hook('sendingDomainEditPageOutput', 1, function($vars) {
// $vars contains domain data
return '<div class="custom-domain-content">Custom domain view</div>';
});
ContactListActions
Adds custom actions to the contact list actions dropdown.
add_hook('ContactListActions', 1, function($vars) {
// $vars contains list row data
$listId = $vars->id;
return <<<HTML
<a class="dropdown-item" href="/custom-action/{$listId}">
<i class="fas fa-cog"></i> Custom Action
</a>
HTML;
});
Controller-Based Output Hooks
Some hooks are used in controllers to get custom output:
AutomationChooseTemplate
Returns custom template selection output.
add_hook('AutomationChooseTemplate', 1, function($vars) {
// $vars contains:
// - type: Template type
// - user: User object
// - list: List data
return '<div class="custom-templates">Custom template selector</div>';
});
AutomationUserProfile
Returns custom user profile output.
add_hook('AutomationUserProfile', 1, function($vars) {
// $vars is the user ID
$userId = $vars[0];
return '<div class="custom-profile-section">Custom profile content</div>';
});
AutomationUpdateBroadcast
Returns custom output when updating a broadcast.
add_hook('AutomationUpdateBroadcast', 1, function($vars) {
// $vars contains broadcast update data
return '<div class="update-status">Broadcast updated successfully</div>';
});
TrackingVariables
Returns custom tracking variables for campaigns.
add_hook('TrackingVariables', 1, function($vars) {
// $vars contains campaign data
return 'custom_tracking_param=value';
});
Best Practices
1. Check Route Before Rendering
Don't inject content on every page if it's only needed on specific ones:
add_hook('addPageHtml', 1, function($vars) {
if (($vars['route'] ?? '') !== 'target.page') {
return '';
}
// Your content
});
2. Use Appropriate Priorities
- 1-3: Critical content that must load first
- 5-10: Standard content
- 10+: Non-critical or dependent content
3. Minimize Inline Scripts
For larger scripts, load external files:
// Prefer this
return '<script src="/js/my-script.js"></script>';
// Over this (for large scripts)
return '<script>/* hundreds of lines */</script>';
4. Handle Missing Dependencies
add_hook('HeadEnd', 1, function($vars) {
// Only load if a condition is met
if (!config('features.custom_theme_enabled')) {
return '';
}
return '<link rel="stylesheet" href="/custom-theme.css">';
});
5. Escape User Data
Always escape user-provided data:
add_hook('TitleBar', 1, function($vars) {
$user = $vars['user'] ?? null;
$name = htmlspecialchars($user->name ?? 'Guest', ENT_QUOTES, 'UTF-8');
return "<span>Welcome, {$name}</span>";
});
6. Return Empty String When Not Applicable
Always return an empty string when no output is needed:
add_hook('AlertBar', 1, function($vars) {
if (!shouldShowAlert()) {
return ''; // Don't return null or void
}
return '<div class="alert">Message</div>';
});