Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Calendar Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Check the platform requirements first. 2.0.0 requires PHP 8.3+, Laravel 13, and Livewire 4. On an older app this is an upgrade-ordering problem before it is a calendar problem — bump PHP and Livewire first, since a partial upgrade will fail at Livewire component render time rather than at install time.

Minimal path to a working calendar:

  1. Install the package and publish its config/assets per docs/quickstart.md.
  2. Add HasCalendarEvents to the Eloquent model you want rendered as calendar entries.
  3. Register that model once (service provider boot(), not a controller) via Calendar::registerModel().
  4. Render the calendar component with EmbedOptions that explicitly lists the sources you want visible.
use Illuminate\Database\Eloquent\Model;
use Vendor\Calendar\Concerns\HasCalendarEvents;

class Task extends Model
{
    use HasCalendarEvents;
}

// AppServiceProvider::boot()
Calendar::registerModel(Task::class);

Where to look first, in order:

  • docs/quickstart.md — the only doc that gives you the end-to-end happy path.
  • docs/api/public-api.md — the contract surface you are allowed to depend on. Read this before subclassing anything, so you know what is extension point vs. internal.
  • The workbench enterprise calendars (tasks, classes, CRM, delivery, overview) — this is the highest-value addition in 2.0.0. They are working reference implementations of five different real-world domains, including the wiring between model registration, providers, and drawer sections. Copy them rather than reconstructing from API docs.
  • docs/troubleshooting.md — keep it open the first time an embed renders empty; that is almost always an allowlist problem in 2.0.0.

First use case: a single-model read-only calendar (e.g. Task by due date) with no custom provider and no drawer customisation. Get that rendering before touching EloquentSeries, EloquentEventProvider, or EventDetailsRegistry — each of those adds a layer that makes an empty calendar harder to diagnose.

Implementation Patterns

Model registration is the new spine. Calendar::registerModel() plus HasCalendarEvents plus EloquentEventProvider / EloquentActionHandler replaces per-calendar ad-hoc data wiring. Register all calendar-backed models in one place (a dedicated CalendarServiceProvider or a config/calendar.php model map iterated in boot()), so a new developer can see the full set of calendar sources at a glance.

Recurrence belongs on the model. EloquentSeries lets a model express its own recurrence instead of duplicating RRULE logic in each provider. Pattern: implement series on the model, let the default EloquentEventProvider expand occurrences, and only write a custom provider when the shape of the data differs — not when only the recurrence differs.

// Model-level recurrence via EloquentSeries
class ClassSession extends Model
{
    use HasCalendarEvents;
    use EloquentSeries; // weekly, with exceptions handled at model level
}

Embed options: allowlist, don't omit. Build EmbedOptions from explicit config, not from whatever the request happens to carry. The 2.0.0 semantics are deny-by-default, so treat every embed as a capability grant:

EmbedOptions::make(
    sources: ['tasks', 'delivery'],
    views: ['month', 'agenda'],
    systems: ['internal'],
);

Drive these arrays from named config keys (config('calendar.embeds.dashboard')) rather than inline literals at call sites — you will need to change them per environment, and an invalid key now throws.

Separate read from write with the action handler pair. EloquentEventProvider is the read path; EloquentActionHandler is the write path (create/move/resize/delete from the UI). Keep authorisation in the action handler (policies, not provider conditionals) so drag-and-drop writes are guarded in one place instead of in each calendar view.

Customise the drawer through the registry, not by overriding the component. EventDetailsRegistry registers content, EventDetailsSection renders a section into the host drawer. This is the sanctioned extension point — registering a section keeps you upgrade-safe across minor releases, whereas forking the drawer component does not.

EventDetailsRegistry::register(
    EventDetailsSection::make('crm-context')
        ->view('calendar.sections.crm-context')
        ->resolver(fn ($event) => $event->source === 'crm'),
);

Mine the five workbench calendars for patterns, not just code. Each maps to a distinct integration shape: tasks = simple model + status, classes = recurrence-heavy, CRM = cross-model relations and drawer sections, delivery = time-window/resource semantics, overview = multi-source aggregation. Pick the closest analogue to your feature before designing anything custom.

Gotchas and Tips

The 2.0.0 breaking change will bite silently in the wrong direction. EmbedOptions::make(sources: []) used to widen to all sources and now denies everything. If you have a spread or conditional that can produce an empty array, you get a blank calendar, not an error. Audit every EmbedOptions::make() call for [] and replace with either an explicit list or an omitted argument. Apply the same audit to views and systems, which changed identically.

Invalid and duplicate source keys now throw. Previously ignored, now rejected. This is good — but it means config assembled from array_merge, env-driven arrays, or DB rows can now blow up at render. Deduplicate (array_unique / array_values) before passing, and validate keys against docs/api/public-api.md at config load so failures surface at boot rather than on a user's calendar page.

Empty calendar is a permissions question first. With deny-by-default embeds, the ordering is: is the source key registered? is it listed in sources? is the model registered via registerModel()? is the view listed? is there data in range? Walk that list in order before touching the provider.

Registration timing matters. Calendar::registerModel() in a lazily-resolved provider or a queued/console context can produce a calendar that works in HTTP and not in scheduled jobs. Register in boot() of a provider that is not deferred.

Upgrade checklist for existing 1.x embeds: (1) bump PHP/Laravel/Livewire, (2) fix empty-array embed options, (3) dedupe/validate source keys, (4) confirm model registration is centralised, (5) re-check any drawer customisation against the new EventDetailsRegistry path — if you forked the drawer, migrate to a registered EventDetailsSection now while the extension API is new.

Debugging aid: the workbench overview calendar is the fastest way to distinguish "package broken" from "my config broken" — if the workbench renders and yours doesn't, the problem is in your registration or embed options, not the library.

Extension points, ranked by upgrade safety: EventDetailsSection / EventDetailsRegistry (safe) → EloquentEventProvider / EloquentActionHandler (safe, expected) → EloquentSeries on models (safe) → subclassing core calendar components (avoid; likely to churn between minors).

Pin the version. A major with breaking embed semantics and a hard Livewire 4 requirement means ^2.0 plus a lockfile commit; don't let a composer update move the whole team onto new embed behaviour mid-sprint.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource