mostafaznv/nova-ckeditor
CKEditor 5 field for Laravel Nova that adds a full-featured WYSIWYG editor to your resources, with image and file uploads through Laravel Storage, media embeds, source editing, and multi-language support. Simple to install and configure.
Architecture fit. The package is a thin, MIT-licensed Nova field wrapper around CKEditor 5: PHP field class + published config + a prebuilt JS bundle registered with Nova. It stores whatever HTML the browser emits into a normal Eloquent attribute, which is the right shape for our architecture — portable HTML in longText, not an editor-proprietary JSON blob. That single decision preserves our exit ramp (package swap, fork, or retreat to Textarea) and is the main architectural reason to consider it. It is an admin-panel authoring tool, not a CMS, DAM, or customer-facing editor; scope creep beyond Nova resource forms is out of bounds.
Integration feasibility. Low technical lift, well-bounded. composer require with a constraint matched to our Nova major, one vendor:publish for config and bundle, a longText column, and a field with fileManager(false) gets a working editor on one resource. Uploads add storage:link, disk/path/type configuration, and server-side MIME and size enforcement — the field's client accept attribute is not a control. Realistic pilot effort: 0.5–1 dev day for a single field, plus a sanitizer decision that is genuinely day-one work, not follow-up.
Technical risk. Three clusters, and they are not equal:
Secondary but predictable: published assets in public/vendor/ go stale silently after composer update; strict CSP blanks the editor (needs style-src 'unsafe-inline', asset origin in script-src, upload domain in img-src); every resource can chain its own options, so config drift produces two visually identical fields storing different HTML.
Key questions to resolve before committing:
mews/purifier, or a shared pipeline? Named owner, day one.Textarea fallback?Stack fit. Laravel + Nova shops only — this is a hard prerequisite, not a soft preference. Assumes MySQL longText (a text column silently truncates at 64KB and will be blamed on the editor), a publicly readable upload disk or controlled URL serving, and a CSP policy we can amend.
Migration path. Pin the version, publish config and bundle, centralize field construction behind a one-method factory (Editors::content()), and stand up a single content column on one low-risk resource — a blog post body or help-article body — with fileManager(false) and no uploads. Prove save → persist → render → re-edit round-trips cleanly, then expand. Import legacy HTML through the sanitizer, never around it, or we seed the database with content our own allowlist will mangle on first re-save.
Compatibility. Two axes to pin: Nova major (4 vs 5 → different package lines) and Laravel major (13 requires 7.9.0+). CKEditor build variant — Classic, Inline, Balloon, Document — is a schema decision, not a style tweak: it changes the HTML emitted, and Balloon/Inline can clip inside Nova's scroll containers. Pick once, write the choice down.
Sequencing (one PR per step):
<script> is stripped.Maintenance. The realistic posture is "pinned, isolated, and replaceable." Every composer update requires a conscious asset re-publish plus nova:publish and a hard refresh; the failure signature is an editor that renders but throws console errors, or toolbars showing plugins we removed. Keep the field behind the factory so a future Nova major that breaks the package means swapping one method body, not auditing a dozen resources. Zero dependents and a single maintainer mean the fallback must be written down, not assumed: portable HTML in longText survives a package swap, a fork, or a Textarea retreat.
Support. The product benefit is reduced developer dependency for formatting, links, and embeds — a cycle-time and support-cost win for non-technical operators. The cost is a new class of ticket ("the editor is blank / lost my formatting") that needs an owner and a triage checklist: provider registered and config published; nova:publish run; JS console 404 on the bundle (asset problem, not PHP); field hidden by hideFromIndex() or a display condition; attribute name mismatched with the column. Localization is per-field, so RTL locales also require translated Nova labels, validation messages, and buttons or the form looks broken.
Scaling. longText columns and image storage grow monotonically; no transformation or CDN layer comes with this package, so media serving cost is ours. Upload endpoints should be rate-limited if lower-trust admins can reach the resource. Editor weight on long-form pages is acceptable for admin usage but is not a customer-facing performance profile — do not repurpose it as one.
Failure modes to plan for (each has a cheap prevention):
text column truncation at 64KB → verify SHOW CREATE TABLE, not the migration file.storage:link → uploads succeed, images 404; it is idempotent, put it in deploy.Ramp-up. Developer: roughly a day for the pilot field, plus sanitizer and upload-policy work that should be scoped as real tasks rather than "polish." Editor: minimal — CKEditor 5 is familiar, and per-field toolbars let us trim short fields (summaries, callouts) while keeping the full set for long-form bodies. Organizational: the genuine ramp-up cost is the decision record — licensing confirmation, upload policy, plugin-set lock, and the written fallback — not the code.
How can I help you explore Laravel packages today?