Skip to main content

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;
});

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

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

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>';
});