millat/laravel-hooks
A lightweight Laravel package for adding hooks and filters to your application, letting you modify behavior at runtime without editing core code. Simple to install and use.
Updated in light of v1.4.0 (Laravel 12 compatibility via composer.json, first-time contributor @coolcrio). No new features, no breaking changes, no deprecations.
Architecture fit. The package ports WordPress's add_filter/add_action/do_action/apply_filters model to Laravel. For a TPM the first question is what gap this fills. Laravel already ships an event dispatcher, listener registration in service providers, dispatch() with return values via Event::dispatch() + $this->dispatch() responses, and the Pipeline for value transformation. The honest answer is that 70–80% of the hooks use case is covered natively. The remaining 20% is a genuinely useful niche: named, priority-ordered, value-mutating extension points that third parties can attach to without touching the core, which is the WordPress plugin contract. That matters if you're building a CMS, a plugin ecosystem, an extensible commerce platform, or a product where customers write integration code against your internals. It matters far less for a conventional SaaS where the team owns the whole codebase — there, hooks become "spooky action at a distance" and undermine Laravel's explicitness. v1.4.0 changes nothing here. Compatibility work is not capability work; the architecture-fit verdict stands unchanged.
Integration feasibility. Low technical friction, and now measurably lower than in the prior assessment. MIT license, Composer-installable, no native dependencies, publishable config, service provider auto-discovery. A spike is an afternoon, not a sprint. The prior gate was Laravel and PHP version support, flagged because "a single-maintainer package can lag on major framework releases." v1.4.0 clears that gate for Laravel 12: the constraint in composer.json has been widened, so the package is current against the latest major. That converts an open question into a verified data point — but read it precisely. The change is a composer constraint bump only, not evidence of a test matrix, CI against multiple Laravel majors, or a published support policy. Treat "supports Laravel 12" as "installs and is expected to work on Laravel 12," and confirm behavior in your spike rather than assuming a tested guarantee.
Technical risk. Concentrated and identifiable, with one item now partially retired and one item newly nuanced:
order.after_save?" becomes a codebase-wide grep rather than a static reference. IDE and static analysis support will be weaker than first-class events. Unchanged.Key questions to answer before committing.
did_action/did_filter-style counters? A hooks system without clean removal is a memory-leak and test-isolation hazard.null — silent corruption, or a hard failure?Stack fit. Unchanged: adopt only where the extension model is a product requirement, not a code-organization preference. The right target is a public extension surface: named hooks your platform fires and documents, and your customers or internal feature teams listen to. The wrong target is refactoring existing internal control flow into hooks for "decoupling" — that trades compile-time clarity for runtime mystery with no external consumer to justify it. v1.4.0 does not create a new reason to adopt; it removes a reason to defer.
Migration path. Do not migrate. Add alongside. Keep native events for internal cross-domain communication; reserve hooks for the versioned extension API. Concretely:
domain.before_action, domain.filter_value), priority banding (0–99 core, 100 default, 200+ customer), and a rule that hook names are a public API and require deprecation cycles.Compatibility. Better than last assessed. PHP constraint should still be checked against your floor, but the Laravel major-version risk is now cleared through 12. Config publishability and overridability are unchanged. Because there are still 0 dependents, you have no ecosystem signal on upgrade pain — and 1.4.0's arrival via outside PR reinforces rather than retires that concern. Budget for the possibility of forking, and note that the fork would be a composer constraint change plus test verification, not a rewrite — the surface area is tiny.
Sequencing. Unchanged, and still the order that de-risks most: spike → confirm the extension requirement is real and externally driven → pilot one hook → establish conventions → document the public surface → expand. Do not invert this by adopting the pattern broadly and then discovering you have no external consumers. The one sequencing adjustment: because the package is in maintenance mode, front-load the internal facade and the fork plan into Phase 1–2 rather than treating them as later hardening.
Maintenance. Negligible code footprint, but the maintenance burden is not zero — it is the burden of vendor risk, and v1.4.0 sharpens the picture rather than softening it. With one maintainer, a maintenance-mode release cadence, and no dependents, the plan is unchanged and should be treated as non-negotiable: pin an exact version (1.4.0), wrap the package behind a thin internal facade (your own Hooks class delegating to it), and accept that a fork is a plausible outcome. The facade remains the single highest-leverage operational decision here — it converts a supply-chain risk into a refactor. Add one item: since Laravel 12 support landed via community PR, put "verify package installs and behaves on our Laravel target" into the framework-upgrade checklist explicitly, with an owner.
Support. No commercial support, no SLA. Rely on GitHub issues and your own reading of the source. v1.4.0 is weak evidence of responsiveness — one merged community PR is a data point, not a pattern, and it demonstrably came from outside the maintainer. For a package this small that is acceptable; document the fork path and assign an owner.
Scaling. Runtime cost is trivial — in-memory array lookups over registered callbacks, negligible against DB and network I/O. The scaling concern is cognitive and organizational: as hook registrations grow, the execution order of any given request becomes a function of registration order across many service providers. Two mitigations are mandatory at scale — deterministic priority bands, and a debug command that dumps all registered hooks with priorities and originating classes. Important: 1.4.0 shipped no such tooling, and the release cadence suggests we should not wait for it. Budget to build the registry-dump command ourselves on top of the facade. Without it, incident response degrades badly.
Failure modes to design against.
Ramp-up. Technically an hour. Conceptually, the WordPress hook mental model is unfamiliar to most Laravel developers and is widely regarded with suspicion in that community. Expect resistance and expect misuse (listeners with side effects registered inside filters). Budget for a short internal writeup: when to use hooks vs. events, naming conventions, and the "hooks are public API" rule. Without that, this package will be used inconsistently and the cost will show up six months later as untraceable behavior — which is exactly the failure mode a thoughtful TPM should be pricing in before the first composer require. v1.4.0 does not change this paragraph at all, and it is the paragraph most likely to determine whether the adoption succeeds.
How can I help you explore Laravel packages today?