samuell/contenteditor-plugin
A Laravel plugin that adds a flexible content editor to your application, making it easy to create, edit, and manage rich text and structured content. It integrates cleanly with existing projects and offers a customizable editing experience for developers and content managers alike.
Before you install anything, read the source. With 40 stars, zero dependents, and a last release from September 2023, you are effectively adopting a small, single-maintainer package. Budget 20 minutes to open vendor/samuell1/contenteditor-plugin/src after install and confirm the actual class names, config keys, and event names — the README is thin and API details below are illustrative.
Install
composer require samuell1/contenteditor-plugin
Then list what's publishable so you know what you're getting:
php artisan vendor:publish --provider="Samuell1\ContentEditor\ContentEditorServiceProvider"
Pick the contenteditor-config / contenteditor-assets tags explicitly rather than running a blanket publish — blanket publishes can drag in unrelated tags.
If it's a Filament plugin (likely given the naming), register it on the panel rather than globally:
public function panel(Panel $panel): Panel
{
return $panel->plugins([
\Samuell1\ContentEditor\ContentEditorPlugin::make(),
]);
}
If instead it registers a service provider + routes, confirm the routes appear with php artisan route:list | grep content.
First use case — prove the round trip on one page. Take a single marketing page (not app UI). Mark one region as editable using whatever convention the package uses (a Blade directive, a data-content-editable attribute, or a component wrapper — check the views the package ships). Then:
APP_DEBUG=true and confirm the editor JS is actually injected (view source, not just the network tab).tail storage/logs/laravel.log and inspect the file or DB row directly.Look first at: the service provider (what it binds/registers), the config file (storage path, allowed extensions, middleware), and the save controller/action (that's your security surface).
Scope it to content, not app UI. The package is designed for front-end pages — landing pages, marketing copy, legal pages, docs. Do not point it at arbitrary Blade views or it becomes an unauthenticated file_put_contents primitive.
Storage strategy — pick one and stick to it:
resources/content/pages/*.html or storage/app/content/. Simple, diffable, git-friendly. Downside: no per-user audit trail or drafts unless you build it.updated_by, timestamps, and revisions for free. This is the path to take anything past a prototype.Gate it hard. Wrap the editor routes in your own middleware, not just the package's:
// routes/web.php or the panel's auth stack
Route::middleware(['auth', 'can:edit-content'])->group(function () {
// package routes, or a thin wrapper controller
});
Define a edit-content gate tied to a role/permission. Never rely on the editor being "hidden" in the UI — the save endpoint is the thing that matters.
Draft → preview → publish cycle. The cleanest pattern with a file-backed editor:
draft/ copy.Cache invalidation is on you. If you render stored HTML inside a cached fragment or compiled Blade, saving content does nothing visible until the cache clears. Hook the package's post-save event (check src/Events) or wrap the save in your own service that also calls Cache::forget("page:{$slug}"). Without this you'll spend an afternoon debugging "my changes don't save."
Sanitize on save, escape on render. Stored HTML is user input:
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
$clean = $sanitizer->sanitize($request->input('content'));
Then render with {!! $clean !!} — raw output is only safe because sanitization happened upstream. Do not skip either half.
Integrate via a thin adapter. Rather than scattering package calls across Blade files, put the read/write behind your own class (ContentRepository), so swapping the package out later is a one-file change. Given the maintenance profile, that adapter is your insurance policy.
"samuell1/contenteditor-plugin": "1.0.3" or whatever the tag is — not ^1.0) and vendor-fork it if you ship to production. A private fork with your own namespace is cheap.composer.json for illuminate/* constraints against your Laravel version. A package this quiet was almost certainly not tested on Laravel 11/12.vendor:publish --force after every composer update will clobber any custom CSS/JS you edited in public/vendor/.... Keep customizations in your own asset pipeline instead.public/ (so nothing is directly executable) and owned by the web user. Watch for traversal if any slug/path segment comes from the request — validate against an allowlist of registered pages.php artisan config:clear. If content is compiled into a Blade view, view:clear too — stale config is the #1 cause of "it's ignoring my settings."Log::debug('content save', $request->all())) before it hits disk. Most failures are a field-name mismatch between the JS widget and the controller, which is silent.Storage::fake('content') to assert file writes, and Http::fake() isn't useful here — hit the real save route with actingAs($admin) and assert the 200 plus the persisted artifact.src/: a config-driven storagedriver/disk, an afterSave event, and published views you can override via resources/views/vendor/contenteditor. Those three give you 90% of customization without touching vendor code.How can I help you explore Laravel packages today?