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

Cms Laravel Laravel Package

liberu-cms/cms-laravel

Liberu CMS for Laravel is a modular content management package for building editable websites and applications. It offers pages, posts, media, menus, SEO tooling, custom content types, and role-based admin features, with clean Laravel integration that helps teams ship CMS-driven sites faster.

View on GitHub
Deep Wiki
Context7

Getting Started

This release adds CMS Events Content as a first-class content type in the package family, sitting alongside pages/news. It ships as a content package plus a matching adapter — API, Filament, or Livewire — so you install exactly one delivery layer for the surface you actually need.

Minimal path:

composer require vendor/cms-events vendor/cms-filament   # or vendor/cms-api / vendor/cms-livewire
php artisan vendor:publish --tag=cms-events-config
php artisan vendor:publish --tag=cms-events-migrations
php artisan migrate
php artisan vendor:publish --tag=cms-events-seeders   # optional demo conference data
composer dump-autoload && php artisan optimize:clear

Pin every package in the family to the same major (^32.0) — the adapters are versioned together and a mismatched driver is the most common install failure.

Where to look first, in order:

  1. config/cms-events.php — model map, route prefixes, timezone source, calendar/feed settings, structured-data toggle.
  2. The published migrations — events, event_sessions, speakers, venues, event_speaker pivot, registration_references. Reading these tells you more about the domain than the docs do.
  3. src/Models — Event, EventSession, Speaker, Venue.
  4. The adapter's namespace — Filament resources, API resource classes, or Livewire components (Calendar, EventShow, SpeakerIndex).

First real use case: a conference page. Create a venue, attach speakers, create an event, add ordered sessions, point a registration reference at your ticketing provider, then confirm three things — the /events/{slug} page renders, the .ics feed downloads, and the JSON-LD passes Google's Rich Results test. That single loop exercises every part of the new feature set.

Implementation Patterns

Pick one adapter, not all three. The packages are designed to be swappable; installing Filament for the back office and the API for a headless front end is a legitimate and common pairing, but installing Filament and Livewire usually means you're duplicating presentation logic. Editor in Filament, render via Livewire or API — not both.

Model the hierarchy as Event → Session → Speaker/Venue. Sessions are children, not siblings: they carry starts_at/ends_at, an ordering column, and a kind-style discriminator (talk, workshop, break, keynote). Speakers are many-to-many with a pivot role field, and the same speaker record is reused across events — never duplicate a speaker per event, or the speaker archive page fragments.

Override models via the config map, not by editing vendor code. Subclass Event, add your own scopes/accessors (e.g. isSoldOut()), then point config('cms-events.models.event') at it. Same pattern for resource classes and Filament resources; re-registering a subclass into the panel is supported and keeps upgrades painless.

Lean on the scopes, don't hand-roll date filters. The package exposes published/upcoming/past-style scopes. A typical index controller is a scoped, eager-loaded query:

Event::query()
    ->published()
    ->upcoming()
    ->with(['venue', 'speakers', 'sessions' => fn ($q) => $q->orderBy('starts_at')])
    ->paginate(12);

Archive is a route + scope, not a boolean. Past events move to an archive index on their own route, keeping the primary listing performant and the SEO story clean (canonical list vs. archived detail pages). Wire archive pagination separately so the main listing stays uncached-and-short while the archive can be cached aggressively.

Calendar feeds want their own cache layer. Generate the iCal output once per event (or per filtered listing), cache it keyed on the event's updated_at, and serve it with an ETag. Anything that rebuilds the feed on every request will fall over the first time a bot subscribes to it.

Registration references are a pointer, not a registration. Store provider, external id, optional deep-link URL, and the ticketing state you care about (open, sold-out, closed). Keep them in their own table with a unique constraint on (provider, external_id) and reconcile via a scheduled job or webhook listener — never make the public page depend on a live call to the ticket vendor.

Structured data belongs in one overridable component. Publish the JSON-LD Blade/class component and extend it rather than injecting scripts in layouts. Encode startDate with the venue's offset, nest sessions as subEvent or an eventSchedule, and include offers only when you actually have ticket data.

Test with factories and travel. The archive/upcoming behaviour is entirely date-dependent — $this->travelTo() around the archive boundary is the only reliable way to test it, and it's worth two tests (one second before midnight, one after).

Gotchas and Tips

  • The whole family moves together. A v32 content package will not boot against a v31 adapter. Upgrade content, API, Filament, and Livewire packages in one commit, and add a constraint like "vendor/cms-events": "^32.0" rather than *.
  • Timezone drift is the number one bug source. Store starts_at in UTC, store the venue's IANA timezone, and convert only at render time. Structured data must emit the offset (2025-05-14T09:00:00+02:00), which is not the same string as the raw UTC value — DST boundaries make this visible twice a year and invisible the rest of the time.
  • Migrations must run after venues/speakers exist. If you install into an existing app, publish and run the events migrations before any of your own migrations referencing event_sessions, and check the FK order on a fresh migrate:fresh — it's the cheapest smoke test there is.
  • Global scopes hide rows in the admin. An upcoming/published scope that also applies in Filament makes past events look deleted. Use the archive scope explicitly in the panel and remember withoutGlobalScope() when debugging "missing" records.
  • N+1 arrives via speakers and nested sessions. The API include mechanism makes this easy to trigger silently — always check a listing endpoint with DB::listen() or Telescope before shipping, and eager-load sessions.speakers when the detail view shows session-level speakers.
  • Slug collisions across Event and Session. If sessions get their own public pages, route-model binding by slug will collide with events on a shared prefix. Scope the binding ({event:slug}/{session:slug}) rather than relying on global uniqueness.
  • Livewire calendar performance. Add wire:key keyed on date + event id inside the grid, avoid re-rendering the whole month on filter keystrokes (debounce, wire:model.live.debounce.500ms), and prefer a full-page component over an embedded one if you need query-string state. wire:navigate between months should preserve scroll position — test it.
  • Filament resource discovery. Register the new resources in your panel provider (or confirm auto-discovery covers the vendor namespace), then check policies: the package ships policies for events/speakers/venues, and tenant-scoped panels will need those policies to respect your tenancy column.
  • Publishing/visibility is not deletion. Archived and unpublished events should still resolve for admins and for direct links, but return 404/410 for the public. Verify both paths — the published() scope plus a soft-delete check is where this usually goes wrong.
  • Debugging toolkit: php artisan route:list --name=events to confirm which adapter registered what, and php artisan vendor:publish --list-style discovery (or the README's tag table) when a config key seems to have no effect — you may be editing an unpublished default.
  • Extension points worth knowing now: the config model map, the JSON-LD component, the events dispatched on publish/unpublish (hook your CDN purge and sitemap regeneration there), and the API resource classes for anything that needs a field shape the default doesn't offer.
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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager