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

Ckeditor Sonata Media Bundle Laravel Package

runroom-packages/ckeditor-sonata-media-bundle

A Symfony bundle that connects CKEditor with the Sonata Media library, letting editors browse, upload, and insert existing media directly from a CKEditor toolbar button. It wires up the necessary routes, templates, and configuration to keep file management in one place.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the bundle and its two hard dependencies — Sonata Media Bundle and a CKEditor integration (either a CKEditor bundle such as friendsofsymfony/ckeditor-bundle / egeloen/ckeditor-bundle, or a manually built CKEditor 4 instance). The bundle itself is thin glue; it does not pull in an editor.

composer require runroom-packages/ckeditor-sonata-media-bundle

Register the bundle manually — there is no Flex recipe. In config/bundles.php:

Runroom\CkeditorSonataMediaBundle\CkeditorSonataMediaBundle::class => ['all' => true],

(Confirm the exact namespace in the package's composer.json; it is a single class named CkeditorSonataMediaBundle.)

Import the routing. Check src/Resources/config/ in the repo for the file name — it will expose at least a media-browse endpoint and usually an upload endpoint:

# config/routes/ckeditor_sonata_media.yaml
ckeditor_sonata_media:
    resource: '@CkeditorSonataMediaBundle/Resources/config/routing.yaml'
    prefix: /admin

Look first at three files to understand the contract:

  1. src/DependencyInjection/Configuration.php — the config tree (media_context, media_format, template overrides are typical keys).
  2. The controller(s) under src/Controller/ — this is where the CKEditor file-browser protocol is implemented.
  3. src/Resources/views/ and src/Resources/public/ or assets/ — the browse template and the CKEditor plugin/JS.

Minimum configuration is telling the bundle which Sonata media context and format (image size) to use:

# config/packages/ckeditor_sonata_media.yaml
ckeditor_sonata_media:
    media_context: default
    media_format: reference   # or 'small', 'big' — match your Sonata context

Then point CKEditor at the browse endpoint. With a CKEditor bundle:

# config/packages/fos_ckeditor.yaml
fos_ckeditor:
    configurations:
        default:
            filebrowserBrowseUrl: '/admin/ckeditor/sonata-media/browse'  # route path from the bundle

First use case to validate end-to-end: open any admin form with a CKEditor field, click the image/browse button, select a Sonata media item in the modal, and confirm an <img> lands in the editor body. If that round-trip works, the integration is wired correctly and everything else is configuration.

Implementation Patterns

Route-backed file browser (CKEditor 4 protocol). The bundle's primary mode is the classic CKEditor 4 file-browser contract: the editor opens a popup/iframe pointed at the bundle's browse route, the user picks a media item, and the server responds with an HTML page that calls back into the opener:

window.opener.CKEDITOR.tools.callFunction(ckeditorFuncNum, mediaUrl, '');

When you configure filebrowserBrowseUrl / filebrowserImageBrowseUrl, you get the picker for free. If you instead need to attach a toolbar button, include the bundled plugin via extraPlugins and match its button name.

Uploads through Sonata providers. If the bundle exposes an upload endpoint, it will delegate persistence to a Sonata provider (image, file, etc.) in the configured context. Keep the context consistent between upload and browse, otherwise media will appear in the Sonata admin but not in the picker (or vice versa).

Embedding media references, not raw URLs. Sonata media URLs are generated per-format at render time. Two patterns:

  • Store the URL (simple, but breaks if you switch CDN/domain or change the format) — acceptable for static marketing sites.
  • Store a media ID / HTML data attribute and resolve to a URL at render via sonata_media Twig helpers — the safer pattern if media may be re-generated or moved. The bundle does not do this rewrite for you; add a Twig filter or a renderer service if you need it.

Reuse the browse endpoint outside CKEditor. Because it is just a controller rendering media in a context, you can hit it directly for custom pickers or Vue/Stimulus widgets, provided you pass CKEditor's expected CKEditorFuncNum query parameter and accept the JS-callback response shape.

Integration with Sonata Admin forms. For non-WYSIWYG fields, use Sonata's own sonata_type_model_list media picker. Keep the two flows separate: this bundle is for content body (CKEditor) images; the admin form widget is for typed media relations. Mixing them via the same context is usually fine, but don't try to make the CKEditor browse controller return a form field value.

Extending behavior. The bundle is small, so extension is usually by:

  • Decorating the browse controller service in services.yaml to add filtering (e.g., only enabled media, only a category).
  • Overriding the browse Twig template via the config's template key (Sonata admin's layout can be swapped for a minimal one if you want the picker outside the admin chrome).
  • Overriding the route path/name in your app's routing import if the default collides with an existing Sonata admin route.

Security wiring. Put the routes behind the same firewall as Sonata Admin (^/admin in security.yaml), and make sure access_control allows ROLE_ADMIN (or whatever role edits content). The CKEditor dialog is an iframe, so an unauthenticated request will render the login page inside the media modal — a common and confusing failure.

Gotchas and Tips

CKEditor 4 only. The filebrowser*Url protocol and the window.opener.CKEDITOR.tools.callFunction callback are CKEditor 4 concepts. If your project is on CKEditor 5, this bundle will not plug in directly — CKEditor 5 uses a different upload adapter and MediaEmbed/ImageInsert plugin API. Confirm your editor major version before adopting.

Response shape is the #1 debugging trap. The browse/upload endpoints must return an HTML document whose inline script calls back into the opener. Returning JSON, a redirect, or a plain 200 OK will make the dialog appear to hang (the file-browser's "OK" button does nothing) with no console error in the parent page. When debugging, open the iframe URL directly in a tab and confirm you see the callback script, not JSON.

CSRF and uploads. CKEditor's uploader posts a multipart form without your Symfony form CSRF token. If the bundle's upload controller does not disable CSRF on that route, you will get a 419/403 that surfaces only as "upload failed" in the dialog. Either use the bundle's provided route as-is (it should already handle this) or add the route to your framework.csrf_protection exclusions — and accept the risk, since the endpoint is admin-only.

Context/format mismatch silently empties the picker. The bundle filters media by the configured media_context. If your uploaded images go into default but the config says news, the picker shows nothing and everything "looks broken" while uploads succeed. Cross-check sonata_media.contexts in config/packages/sonata_media.yaml against the bundle config.

URL portability. If you persist the format-generated URL (e.g., /uploads/media/default/0001/01/thumb_...jpg) into post content, moving the app under a subpath, changing sonata_media.cdn, or regenerating formats breaks old content. Prefer storing the media ID and resolving at render, or at minimum run a one-time rewrite if you migrate.

Asset publishing. If the bundle ships a CKEditor plugin under Resources/public, run bin/console assets:install --symlink (or wire it through Webpack Encore). A missing plugin.js gives you a silent [CKEDITOR] Plugin "sonatamedia" cannot be found in the editor console and no toolbar button.

Route import order. If you also import Sonata Admin routes with a catch-all ^/admin prefix, the bundle's browse route must be imported before the admin import, or it will be shadowed by Sonata's admin dashboard route. Symptom: the modal opens the admin dashboard instead of the picker.

Permissions on the media entity. Sonata Media has its own visibility (enabled) and, if you use the ACL-aware admin, per-user permissions. The bundle's controller typically trusts Sonata's repository filters — if a user can edit content but not see a given media context, the picker will look empty to them. Verify with a non-super-admin user early.

Low-maintenance package. Two stars and zero dependents on the public registry means: pin the version in composer.json, read the controller before upgrading Symfony (the CKEditor callback and sonata_media manager APIs are stable but not contractual here), and keep a small smoke test around the browse route (assertResponseIsSuccessful, assertSelectorExists('script')) so a Symfony/DependencyInjection change that breaks service wiring is caught in CI rather than in the editor.

Extension point for behavior changes. Rather than forking, decorate the browse controller to filter the media query (e.g., only enabled = true, only images, only a given category), and override the Twig template via config if you want a stripped-down picker UI. Both are supported without touching the vendor code, which matters given the package's low release cadence.

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