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 Tinymce Field Laravel Package

bythepixel/nova-tinymce-field

A Laravel Nova field that adds a TinyMCE WYSIWYG editor to your resources, giving users rich-text editing for long-form content. Install via Composer and attach it to any Nova resource to swap plain textareas for TinyMCE's formatting and media tools.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require bythepixel/nova-tinymce-field. There is no migration and usually no config to publish — this is a pure Nova form field — but confirm against the README before assuming, and check composer.json in the vendor directory for the Nova version constraint (this package's last release is April 2024, so treat Nova 4 as the safe target and verify Nova 5 compatibility yourself).
  • The service provider is auto-discovered and its only real job is calling Nova::script() / Nova::style() to inject the TinyMCE bundle into the Nova SPA. Read vendor/bythepixel/nova-tinymce-field/src/ first: the field class tells you which fluent setters exist (options(), height(), and any API-key/CDN helpers), and the compiled JS tells you which TinyMCE version and URL it loads.
  • Add a column — longText rather than text, since text caps at ~64KB and long articles will silently truncate under non-strict MySQL:
$table->longText('content')->nullable();
  • Minimal first use in a Resource:
use Bythepixel\NovaTinyMCE\NovaTinyMCE; // confirm exact namespace/class from the README

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Title')->rules('required', 'max:255'),
        NovaTinyMCE::make('Content')
            ->rules('nullable')
            ->options([
                'menubar'    => false,
                'plugins'    => 'lists link code table',
                'toolbar'    => 'undo redo | bold italic | bullist numlist | link table | code',
                'height'     => 500,
            ]),
    ];
}
  • First use case: a Page/Post/Article resource with a rich body. Open the Nova create screen, confirm tinymce.min.js loads in the network tab, type some bold text, save, then tinker the model and assert the HTML persisted. Once that round-trip works, wire up frontend rendering ({!! $page->content !!} behind a sanitizer) and you have the whole pattern.

Implementation Patterns

  • Create one app-level field class. Subclass NovaTinyMCE as App\Nova\Fields\RichText and put your house defaults (toolbar, plugins, height, branding off, content style) in the constructor. Every resource then uses one class, and swapping the underlying package later is a one-file change.
  • Two presets, not one. A "minimal" preset (bold/italic/lists/link) for short marketing copy and a "full" preset (tables, code, media) for long-form pages. Expose them as static factory methods so RichText::full('Content') reads intent at the call site.
  • Drive options from config. Put toolbar/plugins in config/nova-tinymce.php in your app and merge them per field, so a copy tweak or plugin addition doesn't require touching every resource. Remember config:cache in production.
  • Uploads go through your own endpoint. TinyMCE's images_upload_url and file_picker_callback expect a route that returns { "location": "https://..." }. Nova's temporary-upload endpoint isn't shaped for this, so add a small authenticated controller that validates mime/size and stores to your configured disk. Keep it behind the same auth middleware as Nova.
  • Store HTML, sanitize on write. Use a model mutator or ->fillUsing() with HTMLPurifier (mews/purifier) and an allowlist that matches the tags/classes your frontend CSS actually styles. Sanitizing at write time keeps existing rows clean and makes the stored column trustworthy for feeds and APIs.
  • Detail vs index. This field renders the editor in forms; in detail/index it renders text. Use ->hideFromIndex() for long bodies, and ->displayUsing(fn ($v) => Str::limit(strip_tags($v), 120)) if you want a preview — rendering raw HTML inside an index cell will wreck the card layout.
  • Rules and limits. ->rules('nullable', 'max:65000') where you use text, plus a frontend maxlength via ->options(['max_chars' => ...]) if you need a hard cap. Pair with a validation message that doesn't confuse editors.
  • Localisation. One field per locale (Content (EN), Content (FR)) or wrap in nova-translatable if your version supports it; the field itself is locale-agnostic.
  • Testing. Editor behaviour is client-side, so cover it with feature tests that PATCH the Nova resource endpoint with an HTML payload and assert the stored, sanitized output — not by simulating TinyMCE. Reserve Dusk for a single smoke test that the editor mounts.

Gotchas and Tips

  • Small package, low maintenance signal. Zero stars and one release in 2024 means you are effectively self-supporting. Pin an exact version in composer.json, add the field to your Nova upgrade checklist, and keep the App\Nova\Fields\RichText wrapper so a fork or replacement is contained.
  • TinyMCE Cloud warnings. Out of the box TinyMCE may pull from the cloud and show "This domain is not registered" notices, and it will simply fail in air-gapped or CSP-locked environments. Either set an api_key in options() or self-host TinyMCE and point the field at it. Check your script-src CSP allows whichever origin you use.
  • "Nothing happens in production." Usually cached assets: run php artisan nova:publish and php artisan view:clear after upgrades, and verify the compiled JS is being served rather than a stale published copy.
  • Option merging is not obviously deep. Toolbar and plugin values can be strings or arrays, and whether your override replaces or merges the package default depends on how it builds the tinymce.init payload. Test each override you rely on; when in doubt, pass the complete array rather than a partial one.
  • TinyMCE rewrites markup. It normalises entities, adds <p> wrappers, and strips attributes not in valid_elements. If you need specific frontend classes or data-* attributes to survive, add them to valid_elements/extended_valid_elements or they will vanish on the next edit.
  • XSS. The stored value is raw HTML by design. Never {!! !!} unsanitized user content, and check whether the field's detail component renders HTML unescaped — if it does, your resource detail page is a vector too.
  • Dark mode mismatch. Nova's theme toggle doesn't automatically switch the editor; the canvas stays light unless you set skin: 'oxide-dark', content_css: 'dark'. Accept it or wire it to a user preference.
  • Escaping in content_style. Inline CSS with quotes inside a PHP array inside a JSON payload breaks easily; keep it in a single-quoted string and verify the field still initialises.
  • Debug checklist. Browser console for tinymce is not defined; network tab for a failed script load; Vue devtools to inspect the field's meta/options payload; a tinker dump of the raw model attribute to confirm what was actually saved.
  • Extension points. Prefer subclassing the field and overriding options()/component() over editing vendor files. If you need a genuinely different editor later, the wrapper class is where you swap it — resources shouldn't notice.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings