realzone22 / larahooks
Lightweight, modular hook engine for Laravel, supporting backend processes and Blade sections.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 2
pkg:composer/realzone22/larahooks
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
This package is auto-updated.
Last update: 2025-11-24 03:45:26 UTC
README
A lightweight, modular hook engine for Laravel that enables extensibility in both backend processes and Blade templates. Create flexible, plugin-like architectures with minimal overhead.
Based on esemve/Hook by Bence Kádár.
Features
- 🎯 Simple Hook Registration - Register listeners with priorities
- 🔄 Blade Directives - Use
@shookfor inserting content and@hook/@endhookfor wrapping/modifying content - 🎨 Content Modification - Wrap and modify HTML sections
- 🧪 Testing Support - Mock hooks for easy testing
- 📊 Hook Discovery - List all registered and available hooks
Installation
composer require realzone22/larahooks
Publish the configuration file (optional):
php artisan vendor:publish --tag="larahooks-config"
Basic Usage
Backend Hooks
Register a hook listener in your AppServiceProvider:
use RealZone22\LaraHooks\Facades\LaraHooks; public function boot(): void { LaraHooks::listen('user.created', function ($callback, $output, $params) { $user = $params['user']; // Send welcome email, create profile, etc. }, 10); }
Execute the hook in your code:
use RealZone22\LaraHooks\Facades\LaraHooks; $user = User::create($data); LaraHooks::get('user.created', ['user' => $user]);
Blade Template Hooks
Insertion Points with @shook
Use @shook to define insertion points where content can be injected:
<div class="header">
<h1>Welcome</h1>
@shook('header.notifications')
</div>
<div class="sidebar">
@shook('sidebar.widgets')
</div>
Inject content at these points:
LaraHooks::listen('header.notifications', function ($callback, $output, $params) { return '<div class="notification">New messages!</div>'; }, 10); LaraHooks::listen('sidebar.widgets', function ($callback, $output, $params) { return '<div class="weather-widget">Weather Widget</div>'; }, 10);
Content Wrapping with @hook/@endhook
Use @hook and @endhook to wrap content that can be modified or replaced:
@hook('product.card')
<div class="product">
<h3>{{ $product->name }}</h3>
<p>{{ $product->price }}</p>
</div>
@endhook
@hook('footer.content')
<div class="default-footer">
<p>© 2024 Company Name</p>
</div>
@endhook
Modify or replace the wrapped content:
LaraHooks::listen('product.card', function ($callback, $output, $params) { // Wrap existing content with additional markup return '<div class="featured-badge">Featured</div>' . $output; }, 10); LaraHooks::listen('footer.content', function ($callback, $output, $params) { // Replace entire content return '<div class="custom-footer"><p>Custom Footer Content</p></div>'; }, 10);
Advanced Usage
Hook Priorities
Lower numbers execute first:
LaraHooks::listen('user.login', function () { // Runs first }, 1); LaraHooks::listen('user.login', function () { // Runs second }, 10); LaraHooks::listen('user.login', function () { // Runs third }, 100);
Stopping Hook Execution
LaraHooks::listen('payment.process', function ($callback, $output, $params) { if ($params['amount'] > 1000) { LaraHooks::stop('payment.process'); return 'Payment requires manual review'; } }, 1); LaraHooks::listen('payment.process', function ($callback, $output, $params) { // This will not run if the amount > 1000 return 'Payment processed successfully'; }, 10);
Default Callbacks
Provide a fallback when no hooks are registered:
$content = LaraHooks::get('custom.content', [], function () { return 'Default content when no hooks registered'; });
Passing Parameters
LaraHooks::get('order.created', [ 'order' => $order, 'user' => $user, 'total' => $total ]);
Access parameters in listeners:
LaraHooks::listen('order.created', function ($callback, $output, $params) { $order = $params['order']; $user = $params['user']; $total = $params['total']; // Process order... }, 10);
Combining @shook and @hook
You can combine both directives for maximum flexibility:
<div class="page-content">
@shook('content.before')
@hook('main.content')
<article>
<h1>{{ $title }}</h1>
<p>{{ $content }}</p>
</article>
@endhook
@shook('content.after')
</div>
Register listeners:
// Insert content before main content LaraHooks::listen('content.before', function ($callback, $output, $params) { return '<div class="breadcrumbs">Home > Article</div>'; }, 10); // Wrap main content LaraHooks::listen('main.content', function ($callback, $output, $params) { return '<div class="content-wrapper">' . $output . '</div>'; }, 10); // Insert content after main content LaraHooks::listen('content.after', function ($callback, $output, $params) { return '<div class="related-articles">Related Articles</div>'; }, 10);
Testing
Mock hooks in your tests:
use RealZone22\LaraHooks\Facades\LaraHooks; public function test_user_creation_with_hooks(): void { LaraHooks::mock('user.created', 'mocked response'); $result = LaraHooks::get('user.created', ['user' => $user]); $this->assertEquals('mocked response', $result); }
Run the test suite:
composer test
Hook Discovery
List all registered hooks and their locations:
php artisan hook:list
This command shows:
- All registered hook listeners with priorities
- Hooks found in Blade templates (
@hook/@endhook,@shook) - Hooks called in PHP classes (
LaraHooks::get())
Use Cases
Plugin System
// In a plugin's service provider LaraHooks::listen('admin.menu', function ($callback, $output, $params) { return $output . '<li><a href="/plugin">My Plugin</a></li>'; }, 50);
Theme Customization
{{-- Base theme template --}}
@hook('footer.widgets')
<div class="default-footer-widgets">
<div class="widget">Default Widget</div>
</div>
@endhook
// In child theme service provider LaraHooks::listen('footer.widgets', function ($callback, $output, $params) { return '<div class="custom-footer-widgets">Custom Widgets</div>'; }, 10);
Dynamic Content Injection
{{-- Template with injection point --}}
<div class="dashboard">
<h1>Dashboard</h1>
@shook('dashboard.widgets')
</div>
// Multiple plugins can inject widgets LaraHooks::listen('dashboard.widgets', function ($callback, $output, $params) { return '<div class="analytics-widget">Analytics</div>'; }, 10); LaraHooks::listen('dashboard.widgets', function ($callback, $output, $params) { return $output . '<div class="stats-widget">Statistics</div>'; }, 20);
Event-Driven Architecture
LaraHooks::listen('invoice.paid', function ($callback, $output, $params) { // Update accounting system }, 10); LaraHooks::listen('invoice.paid', function ($callback, $output, $params) { // Send receipt email }, 20); LaraHooks::listen('invoice.paid', function ($callback, $output, $params) { // Update analytics }, 30);
API Reference
LaraHooks Facade
// Register a listener LaraHooks::listen(string $hook, callable $callback, int $priority = 10): void // Execute a hook LaraHooks::get(string $hook, array $params = [], ?callable $callback = null, string $htmlContent = ''): mixed // Stop hook execution LaraHooks::stop(string $hook): void // Mock hook for testing LaraHooks::mock(string $hook, mixed $return): void // Get all registered hooks LaraHooks::getHooks(): array // Get all listeners LaraHooks::getListeners(): array // Get listeners for specific hook LaraHooks::getEvents(string $hook): array
Blade Directives
{{-- Insertion point - content will be injected here --}}
@shook('hook.name')
{{-- Content wrapper - content inside can be modified or replaced --}}
@hook('hook.name')
Content that can be modified or replaced
@endhook
Configuration
The package works out of the box without configuration. If you need to customize behavior, publish the config file and adjust as needed.
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.