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

Nova Ckeditor4 Field Laravel Package

waynestate/nova-ckeditor4-field

A Laravel Nova field that integrates the CKEditor 4 WYSIWYG editor into your admin panel. Add rich text editing to any Nova resource with configurable toolbars, image and file uploads handled through Nova, and straightforward customization for content-heavy applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Prerequisites

  • A Laravel application with Laravel Nova installed (check the package’s composer.json for the supported Nova/PHP versions before installing).
  • A database column large enough for HTML — usually TEXT, MEDIUMTEXT, or LONGTEXT depending on expected content size.

Install

composer require waynestate/nova-ckeditor4-field

If package discovery is disabled, register the package service provider in config/app.php. Most Nova field packages also require publishing their frontend assets:

php artisan vendor:publish --provider="Waynestate\NovaCKEditor4Field\FieldServiceProvider"
php artisan nova:publish
php artisan optimize:clear

The exact provider name and publish tag are in the package README — verify them in vendor/waynestate/nova-ckeditor4-field/ rather than guessing.

Where to look first

  1. vendor/waynestate/nova-ckeditor4-field/src/ — the Nova Field class, which tells you the exact class name, available fluent methods, and how options are passed to CKEditor.
  2. vendor/waynestate/nova-ckeditor4-field/resources/js/ — the Vue component that calls CKEDITOR.replace(); useful when debugging initialization or adding custom plugins.
  3. vendor/waynestate/nova-ckeditor4-field/dist/ — compiled assets actually served to Nova.
  4. README.md and CHANGELOG.md — especially for Nova major-version compatibility notes and the 2.0.x fillAttribute() change.
  5. composer.json — Nova version constraints and autoloaded service providers.

First use case

Add the field to a Nova resource for an existing body / content column:

use Waynestate\NovaCKEditor4Field\CKEditor4Field;

public function fields(Request $request)
{
    return [
        CKEditor4Field::make('Body', 'body')
            ->rules('required', 'max:65535'),
    ];
}

Create or edit a record in Nova and confirm the editor renders. If it does not, check the browser console and the Nova asset registration before changing application code.

Implementation Patterns

Basic resource integration

Treat the field as a form input that stores raw HTML. The package handles the editor UI; you remain responsible for storage, validation, display, and sanitization.

CKEditor4Field::make('Content')
    ->help('Rich text content displayed on the public site.')
    ->rules('required', 'string', 'max:65535'),

Configuring the toolbar and editor behavior

CKEditor 4 is configured through a configuration array. The field typically exposes a fluent method that forwards options to CKEDITOR.replace() — inspect the field class for the exact method name (options(), config(), or similar). A typical pattern:

CKEditor4Field::make('Body')
    ->options([
        'height' => 400,
        'toolbar' => [
            ['Source', '-', 'Bold', 'Italic', 'Underline', 'Strike'],
            ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent'],
            ['Link', 'Unlink', 'Image', 'Table', 'HorizontalRule'],
            ['Format', 'Styles', 'RemoveFormat'],
            ['Maximize'],
        ],
        'allowedContent' => true,
        'extraPlugins' => 'justify,colorbutton',
    ]);

Keep shared toolbar definitions in a small helper class or config file so multiple resources and fields stay consistent:

class EditorConfig
{
    public static function basic(): array
    {
        return ['height' => 300, 'toolbar' => [...]];
    }
}

Fill behavior and the 2.0.1 change

Since 2.0.1, the field’s fillAttribute() returns the parent Nova result by default instead of swallowing it. In practice this means the normal Nova fill pipeline runs for the field: the request value is handed to the model, so attribute mutators, casts, and any other fill logic you rely on are applied as expected when a record is saved.

Consequences worth knowing:

  • If you previously subclassed the field and overrode fillAttribute() only to work around the missing return value, you can usually delete that override and let the parent handle it.
  • If you override fillAttribute() for real reasons, make sure you still return a value (or explicitly delegate to parent::fillAttribute()), otherwise the attribute may not be filled at all.
  • Sanitization written as a model mutator now reliably runs on save through the field, because the parent fill path is used.
// Model: sanitization applied on write
public function setBodyAttribute($value): void
{
    $this->attributes['body'] = (new HTMLPurifier)->purify($value);
}

Displaying the stored HTML outside the form

The package is a form field. For Nova index/detail views, use Nova’s built-in display fields instead:

Text::make('Body')
    ->asHtml()
    ->onlyOnDetail(),

Text::make('Body')
    ->displayUsing(fn ($value) => Str::limit(strip_tags($value), 80))
    ->onlyOnIndex(),

asHtml() does not sanitize. Only render HTML you have sanitized or that was authored by trusted administrators.

Sanitization and content pipeline

A practical pattern is to sanitize on write and store the cleaned HTML:

// In a FormRequest, observer, or model mutator
use HTMLPurifier;

public function setBodyAttribute($value): void
{
    $this->attributes['body'] = (new HTMLPurifier)->purify($value);
}

If HTML must be rendered unescaped in Blade, consider Laravel’s AsHtmlString cast after sanitization, rather than sprinkling {!! !!} throughout views.

Image and file uploads

CKEditor 4 does not ship a working upload backend. If the toolbar includes Image or Upload, you must provide an endpoint and configure CKEditor’s file browser settings:

->options([
    'filebrowserUploadUrl' => route('ckeditor.upload'),
    'filebrowserUploadMethod' => 'form',
])

The endpoint must validate MIME types, size, and authorization, and it must return the JSON/HTML response CKEditor expects. Many teams avoid this entirely by using a separate Nova File / media library field and referencing uploaded URLs in the editor.

Validation and database choices

  • Use longText for realistic article content.
  • Validate with max: matching the column capacity.
  • Consider required only if empty content is truly invalid; CKEditor can submit empty markup.
  • For localized content, use one field per locale and the same config helper.

Testing

At minimum, assert the resource exposes the field and that stored HTML survives a save round-trip — including through any fillAttribute() override you add. If you add custom upload endpoints or sanitization, cover them with feature tests rather than testing the CKEditor UI itself.

Gotchas and Tips

CKEditor 4 is end-of-life

CKEditor 4 reached end-of-life in 2023 and no longer receives security patches. This is the most important risk with this package. For new projects, evaluate CKEditor 5 or a maintained alternative. If you must keep CKEditor 4, restrict editor access to trusted administrators and sanitize output aggressively.

fillAttribute() behavior changed in 2.0.1

Version 2.0.0 and earlier could drop the parent result when filling the attribute; 2.0.1 returns it by default. If you upgraded and now see different stored values (for example, sanitized output where you previously got raw input), that is why. Audit any custom field subclass that overrides fillAttribute() — both upgrading to 2.0.1 and staying on 2.0.0 carry risk here, so pin the exact version you have tested.

Nova version compatibility

This is a small package with a low release cadence relative to Nova major versions. Pin both laravel/nova and this package in composer.json, read the CHANGELOG before upgrading Nova, and test in a staging environment. A Nova upgrade can break field assets or the Vue component even when Composer resolves successfully.

Field renders blank or unstyled

Usually an asset registration issue. Run:

php artisan nova:publish
php artisan optimize:clear

Then hard-refresh the browser and check the Network tab for 404s on the package’s dist/ files. Also confirm the service provider is registered if discovery is disabled.

Content Security Policy conflicts

CKEditor 4 uses inline styles and, depending on plugins, dynamic script evaluation. A strict CSP can prevent initialization. Options:

  • Self-host a custom CKEditor build and set the editor’s basePath.
  • Relax CSP only for the Nova admin path.
  • Remove plugins that require unsafe evaluation.

Duplicate editor instances

If you wrap or extend the field, ensure the CKEditor instance is destroyed on component teardown (CKEDITOR.instances[id].destroy()). Nova modals and InlineRelationships can mount/unmount fields repeatedly, leading to “editor already exists” errors or duplicated toolbars.

allowedContent is not a security boundary

CKEditor’s content filtering controls editor behavior, not server-side safety. A user can submit HTML directly to your API or bypass the editor. Always sanitize on the server — and note that the 2.0.1 fill fix makes mutator-based sanitization behave consistently, which is a reason to prefer it over per-controller cleanup.

Upload endpoint CSRF and response shape

CKEditor’s uploader expects specific response formats and may not include Laravel’s CSRF token automatically. If uploads fail silently, inspect the Network response and configure filebrowserUploadMethod, CSRF headers, or switch to a separate upload field.

Config cache surprises

Laravel’s config cache can retain stale package configuration after install or upgrade. Run php artisan config:clear when changing published config files.

Large content and MySQL limits

Very large HTML payloads can hit max_allowed_packet, request body limits (PHP post_max_size, nginx client_body_buffer_size/client_max_body_size), or validation limits before the database complains. Align these limits with your max: rule and column type.

Debugging checklist

  1. Browser console: CKEditor configuration errors, missing plugins, CSP violations.
  2. Network tab: missing dist/ assets, failed upload requests.
  3. php artisan route:list: confirm any custom upload route exists and uses the correct middleware.
  4. The field class in vendor/: confirm the option method name, how options reach CKEDITOR.replace(), and what fillAttribute() returns.
  5. A minimal Nova resource with only this field: isolates conflicts with other custom fields or scripts.
  6. Save one record and inspect the raw column value to verify whether sanitization ran end-to-end.

Extension points

The practical extension points are the CKEditor configuration array (toolbar, plugins, height, upload URLs) and the surrounding Laravel pipeline (mutators, observers, FormRequests, sanitization, display fields). The fillAttribute() hook is a supported seam since 2.0.1 — always return the parent result unless you have a reason not to. If you need deeper changes, copying the field’s Vue component into your own Nova field package is usually safer than modifying vendor/ directly.

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