gibilogic/tinymce-bundle
A Symfony bundle that integrates the TinyMCE rich text editor into your applications, providing configurable WYSIWYG editing for forms and content fields with minimal setup and easy customization.
First, the framing that matters: gibilogic/tinymce-bundle is a Symfony2 bundle, not a Laravel package. There is no service provider, no facade, no config/tinymce.php, no @tinymce Blade directive. Running composer require gibilogic/tinymce-bundle in a Laravel app will either fail dependency resolution or drag in symfony/framework-bundle ^2.x and its Form/Templating components that Laravel never uses. You cannot install your way to value here.
So the realistic first step is to read it, not install it. The bundle is small; the entire surface area is roughly:
DependencyInjection/Configuration.php — the config tree (toolbar, plugins, theme, height, content_css, etc.). This is the spec you want to copy.Resources/config/services.xml — wiring for the Twig extension and/or form type.Form/Type/* and Twig/*Extension.php — how the init <script> is generated and attached to a field.Resources/public/ — the vendored TinyMCE assets, installed to web/ via assets:install.If you are actually dropped into a legacy Symfony2 app (the only context where this is directly usable): register the bundle in AppKernel::registerBundles(), add a gibilogic_tinymce: block to config.yml, run php app/console assets:install --symlink, and swap a <textarea> for the bundle's field type. That is the entire onboarding.
Your first use case in Laravel is the same one the bundle exists for: take a plain <textarea name="body"> in an admin CRUD form and turn it into a WYSIWYG without hand-writing tinymce.init() in twenty Blade files. Read Configuration.php with that goal, then write a config/tinymce.php that mirrors its keys and a <x-tinymce> Blade component that renders the textarea plus an init script.
Config-tree-as-defaults, per-field overrides. The bundle's real idea is that global defaults live in config and individual fields override a subset. Mirror it:
// config/tinymce.php
return [
'default' => [
'height' => 400,
'menubar' => false,
'plugins' => 'lists link table code',
'toolbar' => 'undo redo | bold italic | bullist numlist | link table | code',
'content_css' => '/css/editor.css',
],
'profiles' => [
'basic' => ['toolbar' => 'bold italic | link'],
'full' => ['plugins' => 'lists link table code image media', 'height' => 600],
],
];
Blade component as the form-type equivalent. This is the direct analogue of the bundle's form type — one component, one place to change editor behavior:
{{-- resources/views/components/tinymce.blade.php --}}
@props(['name', 'value' => '', 'profile' => 'default'])
<textarea name="{{ $name }}" id="{{ $id = 'tinymce-'.Str::random(8) }}">{{ $value }}</textarea>
@once
@push('scripts')
<script src="{{ asset('vendor/tinymce/tinymce.min.js') }}"></script>
@endpush
@endonce
@push('scripts')
<script>
tinymce.init({ target: document.getElementById('{{ $id }}'),
...@json(config('tinymce.profiles.'.$profile, config('tinymce.default'))) });
</script>
@endpush
Asset handling: Vite, not the Symfony asset pipeline. Where the bundle copies Resources/public/ into Symfony's web/ directory, you install tinymce from npm and let Vite bundle it. npm i tinymce then import tinymce from 'tinymce' in resources/js/app.js, or reference it via @vite. This is the single most important port — it keeps version pinning and security patching under your control instead of relying on assets vendored years ago.
Initialization via a Stimulus-style controller or a small Alpine/Vanilla helper. The bundle lazily generates an init script per field. In Laravel, prefer a data-attribute-driven controller so multiple editors on a page stay independent:
document.querySelectorAll('[data-tinymce]').forEach(el => {
tinymce.init({ target: el, ...JSON.parse(el.dataset.tinymce) });
});
Server-side integration. The bundle only injects config; it does not sanitize. In Laravel, route the editor output through a real sanitizer — mews/purifier (HTMLPurifier) or a strict allowlist — in a Form Request or model mutator, not in the editor. This is a deliberate divergence from the bundle, which assumes you handle it.
Multiple editors on one page. The bundle's per-profile config maps cleanly to data-tinymce attributes with the appropriate profiles.<name> JSON. Never rely on global tinymce.init targeting bare textarea selectors — that is the pattern that breaks when you add a second editor.
AppKernel, config.yml, assets:install, Twig extensions — has no Laravel equivalent. Budget for a port, not an install. If anyone frames this as "just composer require," correct them first.tinymce.cloud with an API key. The bundle implicitly assumes a self-hosted local bundle. If you take the cloud path, you inherit key rotation and CSP changes — treat that as a separate integration decision, not part of copying the bundle's pattern.tinymce.init. The bundle emits inline <script> per field. Under a modern Content-Security-Policy that requires a nonce or hash; plan for a @nonce in your Blade component or move init into a compiled JS file with data attributes. This is the most common "editor works locally, blank in staging" failure.<textarea> content because the editor is "safe." This is the highest-severity failure mode of a WYSIWYG integration.web/, not public/. In Laravel, skip the question entirely by using Vite.toolbar, menubar, plugins, content_css, valid_elements); the bundle's config tree mirrors this but adds a Symfony DI layer you do not need. Copy the keys, not the DI structure.@once. If you copy the @once script-include pattern, make sure it appears exactly once per page or the browser will re-execute TinyMCE and re-initialize editors unpredictably. @once combined with @push('scripts') and a layout @stack('scripts') is the reliable combination.config/tinymce.php; (2) the profile system — replicate it as a profiles array; (3) the form-type boundary — replicate it as a single Blade component. Everything else in the bundle (DI, Twig extension) is Symfony plumbing you should drop.tinymce.min.js actually loaded (Network tab), that tinymce.init ran without throwing (Console), that the target selector matched a real <textarea>, and that CSP did not block the init script. Those four cover ~95% of failures and none of them are fixed by the bundle.How can I help you explore Laravel packages today?