tp/redactor-bundle
A PHP bundle that integrates the Redactor WYSIWYG editor into your application, providing centralized editor configuration, asset loading, and reusable form integration. Helps add rich-text editing to admin screens and content forms with less setup and consistent settings across your project.
This bundle is a thin Symfony integration for Imperavi's Redactor WYSIWYG editor: it registers a form type that renders a <textarea> and replaces it with Redactor, plus a small amount of asset/config plumbing. Treat it as a form-type helper, not a full CMS editor stack.
Minimal steps:
composer require tp/redactor-bundle
config/bundles.php:
return [
// ...
TP\RedactorBundle\RedactorBundle::class => ['all' => true],
];
On legacy Symfony, add it to AppKernel::registerBundles()./bundles/...:
bin/console assets:install --symlink
config/packages/*.yaml.$builder->add('body', RedactorType::class);
or override per field:
$builder->add('body', RedactorType::class, [
'settings' => ['toolbar' => 'basic', 'minHeight' => 200],
]);
First use case: replace a plain <textarea> for an article body field with a rich-text editor, keeping the existing entity property as a string and relying on the JS to sync HTML back into the textarea on submit.
Where to look first: the bundle's Form/Type/RedactorType.php and its Twig form theme (form_div_layout.html.twig overrides). That is where the textarea block, asset includes, and per-field settings are wired.
Global defaults + per-field overrides. Put the sensible company-wide toolbar, plugins, and language in the bundle config, then override only what a specific field needs via the settings option. This keeps forms readable and stops config drift across dozens of fields.
Wrap it in your own form type. Because the bundle's type is thin, create an app-level RichTextType that extends or decorates it, sets your standard toolbar, and is what the rest of the codebase injects. You get one place to change editor behaviour, and you are insulated if you later swap Redactor for another editor.
Keep the entity property a plain string. Redactor serialises back into the textarea; do not introduce editor-specific value objects. Sanitise/validate the HTML as a normal string field (@Assert\NotBlank, length checks, and an HTML purifier if output is user-facing).
Reuse the toolbar presets. For content pages use a full toolbar; for comments or meta descriptions use a reduced basic preset (or even disable it and keep a textarea). Passing different settings per field is cheaper than maintaining two form types.
Asset inclusion strategy. Choose one: either let the bundle's form theme include JS/CSS automatically, or include the assets once in your base layout and suppress duplicates. The latter is usually better for performance and avoids ordering problems when multiple forms render on one page.
Integration with admin generators. For EasyAdmin/Sonata, the pattern is to register the Redactor type as the field type for a text property (e.g. map text to RedactorType). Verify the form theme is registered in the admin bundle's Twig config, otherwise you'll get a bare textarea.
File/image uploads. Redactor's image and file buttons need a server endpoint. Wire its upload config to a controller route that returns the JSON shape Redactor expects, and validate MIME type/size there. Keep the upload endpoint out of the bundle config and in your own app code so it is testable.
redactor.js, and the form theme's script block must run after the DOM element exists. If the editor does not appear, inspect script order first, then console errors./bundles/). Re-run assets:install after upgrading, and clear the cache. This is the most common "it was working yesterday" failure.|raw; run it through a purifier or at minimum escape in non-admin contexts.composer why-not and whether the form type still matches the current AbstractType signatures; if not, copy the type into your app and drop the bundle rather than patching vendor code.bin/console debug:form RedactorType (or your wrapper type) shows the resolved options and parent type — useful to confirm whether settings were actually applied.How can I help you explore Laravel packages today?