stinger/ckeditor-widget-bundle
A Laravel/PHP package that bundles CKEditor widgets for easy integration. It provides ready-to-use widget assets and configuration to add custom widgets to CKEditor, helping you build richer content editing experiences with minimal setup.
First, check the framework. stinger/ckeditor-widget-bundle is a Symfony 2 bundle, not a Composer library and not a Laravel package. There is no ServiceProvider, no Facade, no config/*.php to publish, and nothing in the repo that Laravel's container can autoload into a useful state. If you are on Laravel 9+/PHP 8, the composer require will likely fail on symfony/symfony version constraints before you even see the code.
So "getting started" splits into two real paths:
Path 1 — you inherited a Symfony 2 app that already lists it. Look at these files, in this order:
composer.json — note the Symfony/PHP constraints and the autoload PSR-0/PSR-4 mapping. This tells you the bundle namespace (StingerSoft\CKEditorWidgetBundle\StingerSoftCKEditorWidgetBundle style).DependencyInjection/*Extension.php — this is the entire substance of the bundle. It almost certainly calls prependExtensionConfig() or a container parameter to register the widget plugin path with whichever CKEditor bundle you're also using (Ivory/FOS-style: a plugins: path plus extra_plugins: ['widget']).Resources/public/ (or Resources/assets/) — the actual CKEditor 4 widget plugin directory (plugin.js, icons/, lang/, dialogs/).README.md — assume it is a two-line stub; the DI extension is the real documentation.Register it in app/AppKernel.php (new StingerSoft\CKEditorWidgetBundle\StingerSoftCKEditorWidgetBundle()), run assets:install --symlink, and load a page with a CKEditor instance. Open the browser console and check CKEDITOR.plugins.registered.widget exists.
Path 2 — you're on Laravel and want the capability, not the bundle. The capability is "let editors insert reusable, draggable blocks (callouts, image-with-caption, embeds) into rich text, with a dialog to edit them." The first use case to build is a single callout widget with one dialog field. Do not try to port the bundle; take the plugin files from a CKEditor 4 custom build (or the full CKEditor 4 distribution, which ships widget) and copy plugins/widget plus its dependencies into public/vendor/ckeditor/plugins/.
Pattern A — Symfony DI (what the bundle is for). The bundle's job is one line of config you'd otherwise hand-write. The shape is roughly:
# config.yml — verify against the DI extension, not this snippet
ivory_ck_editor:
configs:
default:
extra_plugins: ['widget']
plugins:
widget:
path: "bundles/stingersoftckeditorwidget/widget/"
The point: one place declares the plugin path and one place adds it to extraPlugins. Every editor instance inherits it. If you find yourself repeating widget in YAML per-form, you've missed the bundle's intent.
Pattern B — Laravel, manual wiring (the realistic path). Put the config in one PHP array, not in twenty Blade views:
// config/ckeditor.php
return [
'extra_plugins' => ['widget', 'lineutils', 'dialog', 'fakeobjects'],
'plugin_paths' => ['widget' => '/vendor/ckeditor/plugins/widget/'],
];
Then one Blade partial or component that emits the config as JSON on a data- attribute and calls CKEDITOR.replaceAll with a callback. Views only ever set data-ckeditor-profile="default".
Pattern C — custom build. CKEditor 4's "Standard"/"Basic" builds do not contain widget or its dependencies. You either use the Online Builder / grunt build from ckeditor-dev with widget included, or copy the plugin dirs from the full package. In a Laravel app with Vite, treat the whole ckeditor/ tree as static assets (publicDir or a copy step) — do not try to bundle plugin.js through the module graph; it sniffs CKEDITOR.plugins.addExternal and absolute script paths.
Pattern D — CKEditor 5, if you're starting fresh. There is no widget plugin in CKEditor 5; the equivalent is a custom plugin using toWidget, toWidgetEditable, an upcast/downcast converter pair, and a schema registration for your container element. Budget a day for what the CKEditor 4 plugin gives you for free.
Pattern E — verification loop. For any of the above: load the editor, confirm CKEDITOR.plugins.registered.widget, insert a widget, save, reload the record. If the widget is no longer draggable/edit-on-double-click after reload, the problem is server-side HTML sanitization, not the plugin — see below.
widget requires lineutils, dialog, fakeobjects (and the dialog plugin needs dialogui). If you add only widget to extraPlugins on a standard build, you get a console warning and no widget button — not an exception. Add all four explicitly.allowedContent: true everything works; the moment you tighten it you must allow figure, figcaption, div[class], and data-* (extraAllowedContent: 'figure; figcaption; div(!*)[data-*]'). Symptom: widget appears in the editor but saves as plain markup.data-cke-widget-data / data-widget attributes. HTMLPurifier (Laravel's mews/purifier, or any strict allowlist) strips them, so the saved HTML looks fine but is dead on reload. Allowlist data-widget and data-cke-* on the relevant tags, and sanitize after the widget upcast has run — or accept one-way rendering and re-instantiate on the server./vendor/ckeditor/plugins/widget/) or absolute. Symfony's assets:install symlink-vs-copy and Laravel's Vite dev server (different port/origin) both break relative paths that work in production. Test in both vite dev and a built bundle.AppKernel, and bundle inheritance was deprecated — the DI extension as written may not even be loadable. Do not put this on a critical path; vendor the Resources/public plugin directory into your own repo and delete the dependency.symfony/symfony: ~2.x and php: >=5.3 constraints. You can force with --ignore-platform-reqs for Symfony, but not for Laravel — there is nothing for the framework to boot.[CKEDITOR] Plugin "widget" not found; CKEDITOR.plugins.registered in the console; confirm extraPlugins is a comma string in CKEditor 4 config (an array is silently coerced in some paths); hard-refresh — CKEditor caches plugin scripts aggressively.DependencyInjection extension — it's ~50 lines and that's the whole bundle. In Laravel, your extension point is the config array plus a Blade component; wrap CKEDITOR.replace so profiles (minimal / full / comment) are config keys, never per-view arguments.How can I help you explore Laravel packages today?