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 Package

noerd/cms

A lightweight Laravel CMS package for adding editable pages, reusable content blocks, navigation, and basic SEO to custom apps. noerd/cms integrates with Blade and Eloquent, giving developers a simple admin-friendly way to manage site content without a heavy CMS.

View on GitHub
Deep Wiki
Context7

Getting Started

This release is a structural change, not just a feature drop — treat the upgrade as a small migration project rather than a composer update.

  1. Upgrade path first. Run composer update and then php artisan migrate before touching any views. The migration consolidates existing pages and elements into the new shared contents / content_elements base while preserving ids, so any hard-coded references, polymorphic relations, or cached URLs keyed on the old ids should still resolve. Verify this on a staging copy with real content — id preservation is the one thing you cannot easily roll back.
  2. Read the diff on the removed classes. EditsContentElements, element-page-detail, and element-picker-modal are gone. Grep your app (and any first-party modules) for those names. EditsContentDocument is the replacement concern — anything that previously composed EditsContentElements into a Livewire component or page class needs to switch.
  3. Check your content types register. Any model that used to be a "page" or a standalone element now needs the ExtendsContent concern and an entry in ContentTypeRegistry. Look at the package's service provider for how core types register theirs; mirror that in your own provider's boot().
  4. Publish/build the editor assets. The Tiptap bundle is served through the cms.asset route from dist/build. If you previously published JS assets to public/, remove the stale copies so you aren't serving an old editor alongside the new one.

First use case: open an existing page in the admin, confirm the running text renders, then type // on a blank line and insert an element. That single flow exercises the migration, the registry, the new document concern, and the asset route at once.

Implementation Patterns

Register content types explicitly. The ContentTypeRegistry is the extension seam now. A typical registration exposes a key, a label, a model class using ExtendsContent, and the element types it accepts:

// AppServiceProvider::boot()
ContentTypeRegistry::register('article', ArticleContent::class)
    ->label('Article')
    ->elements(['rich_text', 'image', 'embed']);

Keep registrations in a dedicated provider (CmsServiceProvider) rather than AppServiceProvider so module-level content types stay self-contained.

Model the concern, don't duplicate it. ExtendsContent is what makes a model addressable by the editor. Business models (Article, Product, LandingPage) should use ExtendsContent and let the package own the contents row, rather than each model inventing its own body column. If you have legacy body / content columns, plan a one-way copy into a rich_text element and leave the old column read-only for a release.

Render running text through the element pipeline. Don't {!! $content->body !!}. Running text is a rich_text element like any other, sanitized on save — render it through the same element-resolution loop you use for images/quotes so ordering and nesting stay consistent:

@foreach ($content->elements as $element)
    @include("cms.elements.{$element->type}", ['element' => $element])
@endforeach

Treat rich_text as one element among many, not a special case. Because // inserts an element at the cursor with inline field editing, the document is a flat, ordered sequence of elements where rich_text runs can appear multiple times. Your front-end ordering logic must respect the element position column, not "rich text first, then blocks."

Sanitization is a save-time concern. Since running text is sanitized on save, seeders, imports, and API writes that bypass the editor must sanitize too. Wrap programmatic content creation in a small action class that runs the same sanitizer rather than relying on the editor path.

Asset route in production. The cms.asset route serving dist/build means the editor bundle is served by Laravel, not your CDN. Either accept that (fine for admin-only traffic) or proxy/rewrite the route through your CDN with a long cache header — the route name is stable, so a Route::get override or a middleware-level cache header is the cleanest hook.

Incremental rollout. Because content types are opt-in via the registry, you can migrate one type at a time: register page, verify editing, then register the next. Don't flip every type in one deploy.

Gotchas and Tips

  • Id preservation is load-bearing. The migration keeps ids for pages and elements. If you have an elementable_id/elementable_type morph map, confirm the type strings still match what the new contents table stores — a morph alias change here will silently orphan relations. Write a one-off assertion command that counts orphaned elements before and after.
  • EditsContentElements removal breaks silently-ish. Missing Livewire concerns usually surface as a "property not found" or a trait-not-found fatal, but custom components that extended the old concern may still boot while losing the editing behaviour. Grep for element-picker-modal usages too — the picker modal was likely rendered from a Blade partial you copied into your own views.
  • // is a trigger, not content. If users legitimately need a literal // at the start of a line (URLs, paths, code snippets), test the escape behaviour before you ship. This is the most likely source of support tickets.
  • Multiple rich_text elements per page. Anyone writing queries against content_elements should not assume exactly one rich-text row per content. Use orderBy('position') and handle zero-or-many.
  • Sanitizer config drift. Sanitization runs on save, so tightening the allowlist later won't retroactively clean stored HTML — it only affects new saves. If you tighten it, run a backfill pass over existing rich_text rows.
  • Stale published assets. The move to dist/build + cms.asset means any previously published editor JS in public/vendor/... is now dead weight and, worse, may be loaded by an old layout. Clear it and check your layout for a leftover @vite/<script> reference.
  • Route caching. cms.asset is a package route; if you run route:cache in deploy, confirm it's registered before the cache is built (a package provider that registers routes in boot() after a conditional can bite you). Also check that your auth middleware doesn't accidentally protect the asset route — the editor will load a blank pane rather than error.
  • Extension point for custom element types. Adding a content type is documented via the registry; adding a new element type is the less obvious seam. Expect to need both a renderer view and an inline editor field definition — check whether the package exposes a field-schema contract before writing your own; if it doesn't yet, keep custom element types minimal until it does.
  • Debugging the editor. If inline element fields don't appear, check in this order: registry entry → ExtendsContent on the model → asset route responding → browser console for failed bundle chunks. A 404 on cms.asset presents as an editor that renders static text but never becomes interactive, which is easy to misdiagnose as a permissions issue.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package