Contensio logo

UI render hooks

Named injection points in core Blade templates. Register a callback that returns HTML — it's inserted in place on every render.

Since 1.0.0

UI render hooks are extension points baked into core Blade templates. A plugin registers a callback with Hook::add(); core calls Hook::render() at the named point and injects the concatenated output.

This is separate from action and filter hooks — it's specifically for injecting HTML into the admin or frontend UI without overriding templates.

How to register

use Contensio\Support\Hook;

Hook::add(string $name, callable $callback, int $priority = 10): void

The callback must return a string. Return '' to render nothing conditionally.

How it works in templates

Core templates call:

{!! \Contensio\Support\Hook::render('hook.name') !!}
{!! \Contensio\Support\Hook::render('hook.name', $arg) !!}

All registered callbacks run in priority order; their output is concatenated and rendered raw (unescaped).


contensio/admin/login-after-form

Location: Directly below the username/password form on /login
Arguments: none
Since: 1.0.0
Source: core/resources/views/auth/login.blade.php

Use this point to add alternate sign-in options — social login buttons, magic links, SSO entry points.

Hook::add('contensio/admin/login-after-form', function (): string {
    return view('my-plugin::partials.login-buttons')->render();
});

Notes

  • Renders on every login page load, including after a failed attempt.
  • Multiple plugins can register — output is concatenated in priority order.
  • The output sits inside a narrow single-column layout. Use utility classes that fit a column (avoid full-width grids).

contensio/admin/profile-sections

Location: Below the form on the admin user profile page (/admin/profile)
Arguments: $user — the currently authenticated user model
Since: 1.0.0
Source: core/resources/views/admin/profile/index.blade.php

Use this point to add extra sections to the admin profile page — connected accounts, API tokens, notification preferences.

Hook::add('contensio/admin/profile-sections', function ($user): string {
    if (! $user) return '';
    return view('my-plugin::partials.profile-section', compact('user'))->render();
});

Notes

  • $user is the authenticated admin user. Always guard against null.
  • Renders inside the main profile card column. Match the visual style of existing profile sections — use <div class="border-t border-gray-100 pt-6 mt-6"> as a separator.

contensio/admin/settings-cards

Location: Inside the grid on the Configuration hub (/admin/settings)
Arguments: none
Since: 1.0.0
Source: core/resources/views/admin/settings/index.blade.php

Use this point to add your plugin's settings card to the central Configuration hub, so users can find your settings in the same place as all other settings.

Hook::add('contensio/admin/settings-cards', function (): string {
    return view('my-plugin::partials.settings-card')->render();
});

Example card template

{{-- my-plugin::partials.settings-card --}}
<a href="{{ route('my-plugin.settings') }}"
   class="block bg-white border border-gray-200 rounded-lg p-5 hover:border-gray-300 transition-colors group">
    <div class="flex items-center gap-3 mb-2">
        <div class="w-8 h-8 bg-blue-50 rounded flex items-center justify-center">
            <i class="bi bi-gear text-blue-500"></i>
        </div>
        <h3 class="font-semibold text-gray-900">My Plugin</h3>
    </div>
    <p class="text-sm text-gray-500">Configure My Plugin settings.</p>
</a>

Notes

  • The hub uses a responsive CSS grid (grid-cols-1 md:grid-cols-2 lg:grid-cols-3). Your card should be a single grid cell — a link to your dedicated settings page, not the settings form itself.
  • Keep the card concise: icon, title, one-line description.

contensio/admin/dashboard-quick-actions

Location: Header action bar of the admin dashboard (/admin)
Arguments: none
Since: 1.0.0
Source: core/resources/views/admin/dashboard/index.blade.php

Use this point to add shortcut buttons to the dashboard header — quick-create links, import triggers, or any action your plugin exposes to editors.

Hook::add('contensio/admin/dashboard-quick-actions', function (): string {
    return '<a href="' . route('my-plugin.create') . '"
               class="inline-flex items-center gap-2 px-4 py-2 bg-white border border-gray-200
                      rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors">
                <i class="bi bi-plus-lg"></i> New Item
            </a>';
});

Notes

  • Renders in the top-right area of the dashboard alongside any core quick-action buttons.
  • Output should be one or more <a> or <button> elements styled as small action links.

contensio/admin/dashboard-stats

Location: Below the core stat cards row on the admin dashboard
Arguments: none
Since: 1.0.0
Source: core/resources/views/admin/dashboard/index.blade.php

Use this point to inject additional stat cards after the built-in row (posts, pages, media, comments). Matches the existing card grid.

Hook::add('contensio/admin/dashboard-stats', function (): string {
    $count = \MyPlugin\Models\Item::count();
    return view('my-plugin::partials.dashboard-stat', compact('count'))->render();
});

Notes

  • Core uses a responsive stat card grid. Return one or more card <div> elements matching the core card style so they fit visually.
  • Keep queries fast — this fires on every dashboard load.

contensio/admin/dashboard-widgets

Location: Between the content panels (recent posts, recent comments) and the activity log on the admin dashboard
Arguments: none
Since: 1.0.0
Source: core/resources/views/admin/dashboard/index.blade.php

Use this point to inject full-width or half-width panels — summaries, charts, approval queues, or any at-a-glance data your plugin manages.

Hook::add('contensio/admin/dashboard-widgets', function (): string {
    $items = \MyPlugin\Models\Item::latest()->limit(5)->get();
    return view('my-plugin::partials.dashboard-panel', compact('items'))->render();
});

Notes

  • The dashboard at this point is full-width. Your panel can use the full container or be wrapped in a grid alongside other injected panels.
  • Return '' if there is nothing to show (e.g., no items yet) rather than rendering an empty panel.

contensio/admin/dashboard-after

Location: Below the activity log — the very bottom of the admin dashboard
Arguments: none
Since: 1.0.0
Source: core/resources/views/admin/dashboard/index.blade.php

Use this point for secondary or supplementary content that should not compete with the main dashboard area — onboarding checklists, upgrade notices, plugin-specific activity feeds.

Hook::add('contensio/admin/dashboard-after', function (): string {
    if (MyPlugin\Support\Config::get('setup_complete')) return '';
    return view('my-plugin::partials.setup-checklist')->render();
});

Notes

  • Fires after all other dashboard content. Suitable for lower-priority information.
  • Onboarding or setup notices are a good fit here; they don't interrupt the main workflow.

Checking if a hook has callbacks

if (Hook::has('contensio/admin/login-after-form')) {
    // at least one callback is registered
}

Useful for wrapping hook output in a container that should only render when there's something to show:

@if(\Contensio\Support\Hook::has('contensio/admin/login-after-form'))
<div class="mt-6 border-t border-gray-100 pt-6">
    {!! \Contensio\Support\Hook::render('contensio/admin/login-after-form') !!}
</div>
@endif

Error handling

If a callback throws, the exception is reported via report() and that callback's output is skipped. Other registered callbacks continue to run. The page renders normally.


See also