karnoweb/laravel-calendar
A Laravel package for working with calendars, adding reusable calendar functionality to your PHP applications. Integrates easily with Eloquent models and Blade views so you can build and display date-based features with minimal setup.
Architecture fit. karnoweb/laravel-calendar is a Laravel calendar package whose 2.0.0 release materially changes its architectural shape: it now requires Livewire 4, which makes it a server-rendered Livewire component library rather than a generic Laravel/Blade package with optional headless output. That answers the earlier open question — output is view-coupled to Livewire, and a SPA/mobile client would need a separate API layer we build ourselves. Fit is still strongest where the calendar is a supporting concern (scheduling, bookings, availability, publishing dates) in an app already running Livewire 4 on Laravel 13. For anything else it is now a much narrower fit than the 1.x line was.
Integration feasibility. Effort is lower than 1.x on the data side — HasCalendarEvents, Calendar::registerModel(), EloquentEventProvider and EloquentActionHandler constitute a first-party Eloquent contract, so no custom adapter is needed to source events. EloquentSeries moves recurrence into model space, and EventDetailsRegistry / EventDetailsSection give a supported extension point instead of view overrides. Documentation is now a genuine asset (quickstart.md, examples/*, public-api.md, troubleshooting.md), which removes most of the discovery cost flagged previously. The offsetting cost is environmental: PHP 8.3+, Laravel 13, Livewire 4 is a frontier stack, and the major-version jump carries a real behavioral break (see risk).
Technical risk. Three material changes from the prior assessment:
sources / views / systems arrays previously widened to all; they now deny. Invalid or duplicate embed source keys are rejected rather than ignored. Security-wise this is the right default, but it is a silent fail-closed flip: any existing EmbedOptions::make(sources: []) call that relied on the permissive default will render nothing after upgrade. It will not error — it will just show an empty calendar. Inventory every such call before bumping.Calendar::registerModel() makes the package aware of our Eloquent models. That is convenient and increases the risk that the package's event model becomes the system of record. The internal-interface wrapper recommendation now matters more, not less.Residual risk is lower than before on information (the changelog is substantive and the public API is documented — the 1.0.2 opacity problem is resolved) and roughly unchanged on correctness: DST handling, recurrence exceptions, and test coverage are still unverified. Livewire 4 is itself a young major, so we inherit its ecosystem-maturity and release-cadence risk on top of the vendor's.
Key questions.
EmbedOptions? Is there a deprecation notice or shim for the old widen-to-all behavior, or is it a hard cutover?EloquentEventProvider assume a specific schema/column contract, and can it be overridden for existing event tables without reshaping them?registerModel() register by class, table, or morph alias — and what happens on duplicate registration across packages?EloquentSeries specifically?docs/api/public-api.md considered the stable contract under semver from 2.0.0 forward?EloquentSeriesn`) — cosmetic, but worth a sanity check that the changelog is generated, not hand-verified.Stack fit. Gate on environment first: PHP 8.3+, Laravel 13, Livewire 4. If any of those fail, stop — do not plan a workaround. Second gate: confirm we actually want a Livewire-rendered calendar surface. If the product needs JSON for a mobile or SPA client, this package does not provide it and we should evaluate a headless alternative instead.
Migration path. Greenfield: install, publish config, add HasCalendarEvents to the event model, Calendar::registerModel(), render. Faster than 1.x thanks to the quickstart doc. Brownfield from 1.x: treat as a planned upgrade, not a routine bump. Sequence — read the diff for EmbedOptions, grep for empty-array construction, exercise each embed in staging, then upgrade. Keep the thin CalendarService wrapper from the prior plan and route all package calls through it; the new registry makes bypassing the wrapper tempting and that is exactly the trap. Do not let Calendar::registerModel() become the only definition of our event schema.
Compatibility. Verify in order: PHP 8.3+, Laravel 13, Livewire 4 (and that our Livewire components don't collide with the package's), published Livewire/JS asset overlap with our front-end build, Carbon constraints, and DB indexes on the date columns the Eloquent provider queries. If we run other Livewire component libraries, check for Alpine/asset duplication.
Sequencing.
HasCalendarEvents, render one real view, and exercise the EmbedOptions deny-by-default behavior explicitly — including an intentional empty-array case to confirm the fail-closed result.EloquentSeries, not just the sample calendars.2.0.0 exactly and commit the lockfile.Maintenance. Ongoing footprint rises modestly. The Eloquent registry and documented extension points reduce view-forking (good — published views were the main drift surface in 1.x), but the package is now tethered to Livewire 4, so its upgrade cadence is coupled to Livewire majors and so is ours. We inherit the Livewire 4 → 5 migration on the vendor's schedule, not ours. Assign a periodic check on upstream activity and on whether a 1.x security backport path exists for anything still on the older line.
Support. Community/GitHub issues only, no vendor SLA. Documentation quality improved enough to lower day-to-day support load — troubleshooting.md and public-api.md are the difference between "ask the one engineer who knows" and "read the doc." Internal ownership still needs to be a named engineer accountable for the calendar domain. Document the wrapper and the embed-authorization policy in-repo; the deny-by-default change is precisely the kind of thing that generates support tickets six months later when nobody remembers why an embed is blank.
Scaling. Rendering cost is Livewire server-round-trip cost now, which is a different profile than static Blade output: each view/navigation is a Livewire request. Budget for request volume, not just query volume. Database pressure remains on date-range retrieval and recurrence expansion; index the date columns the EloquentEventProvider queries and cap rendered ranges. Test recurrence expansion with realistic multi-year series, not the shipped workbench samples — those are demos and will make performance look better than production.
Failure modes.
EmbedOptions with empty sources/views/systems renders nothing, silently, with no error. Detect via pre-upgrade grep and staging walkthrough.EloquentSeries.registerModel() conflicting across packages, or the provider assuming a column layout our tables lack.Ramp-up. Happy path is faster than 1.x — the quickstart and examples should get a Laravel-fluent developer to a working calendar in a few hours. The slow part remains domain correctness: recurrence semantics, timezone policy, exception handling, and now embed authorization semantics. That is multi-day regardless of package. Mitigate with a short internal write-up of our date/timezone conventions plus a regression test suite pinned to known-tricky dates and to the embed deny-by-default contract.
Verdict on 2.0.0. Materially different package from the one assessed at 1.0.2, and the assessment changes with it. Positives: first-party Eloquent integration, model-level recurrence, supported extension points, and real documentation — the information risk that dominated the prior review is largely resolved. Negatives: a frontier-stack requirement (PHP 8.3 / Laravel 13 / Livewire 4) that gates out most current apps, a fail-closed breaking change in embed authorization, and deeper coupling to both the vendor and Livewire. Revised posture: viable for supporting-calendar use cases, conditional on (a) the target app already running Laravel 13 with Livewire 4, (b) an audit of every EmbedOptions call site before upgrade, and (c) a recurrence/DST spike against EloquentSeries. If we are not on that stack, this is not a "maybe later this quarter" item — it is blocked, and we should plan around 1.x or an alternative until the platform upgrade lands.
How can I help you explore Laravel packages today?