innomedio/sulu-image-optimizer-bundle
A Sulu CMS bundle for automatic image optimization—compresses and resizes uploaded media to cut file sizes and speed up page loads while preserving visual quality. Integrates with Sulu's media management so images are optimized without extra manual steps.
Require and register. composer require innomedio/sulu-image-optimizer-bundle. Symfony Flex may auto-register it; otherwise add the bundle class to config/bundles.php. Check the package's composer.json constraints against your Sulu and Symfony versions. Pin at minimum ^3.1 — v3.1 fixed uppercase-extension uploads (.JPG, .PNG) that previously blew up with UnsupportedImageFormat, plus related format-detection and ignore_types handling. Older tags carry that bug. The package's maintenance history is thin (historically archived with minimal stars/dependents), so even with a 3.1 patch release, treat version drift as your first risk and review the repo's recent commit activity before adopting.
Read the wiring first. Open vendor/innomedio/sulu-image-optimizer-bundle/ and look at DependencyInjection/ and Resources/config/services.yaml. The key question is which Sulu service it decorates — most likely sulu_media.media_manager or the media storage adapter. That single fact tells you where in the upload lifecycle optimization happens. Confirm with bin/console debug:container sulu_media.media_manager --show-arguments.
Install optimizer binaries. These bundles typically shell out to jpegoptim, optipng, pngquant, gifsicle, svgo, and/or cwebp. Add them to your Docker image or server provisioning and verify with which jpegoptim inside the runtime container. Without them, uploads either silently skip optimization or throw.
First use case. Upload a 3–5 MB JPEG through the Sulu admin into a media collection, then compare the file stored under your media storage (local var/uploads or S3) with the original. Confirm the media record still renders in the admin and that Sulu's image formats generate. Then repeat with a deliberately uppercase-extension file (PHOTO.JPG) — that's the exact regression v3.1 addresses, and it's a one-second check that tells you whether you're actually on the fixed version. That one test validates wiring, binaries, config, and version together.
Configuration. Publish or override the bundle config (typically config/packages/innomedio_sulu_image_optimizer.yaml or a sulu_image_optimizer key). Start with only enabled formats and quality. The ignore_types key (touched by v3.1) controls which mime types are skipped — verify its expected format against the bundle's own docs/tests before relying on it, since format-detection changes in 3.1 may alter what strings it accepts. Run bin/console cache:clear after changes.
Drop-in default. The primary pattern is zero-code: the bundle hooks the media save path, so uploads via the admin, MediaManagerInterface::save(), or the Sulu media API are optimized before persistence. Treat it as infrastructure, not application code.
Verify the decoration point. Confirm whether it decorates sulu_media.media_manager (optimizes the UploadedFile before storage) or the storage adapter (optimizes after write). The former is cleaner and preserves Sulu's mime/extension handling. If the bundle doesn't expose this clearly, a small decorator of your own around MediaManagerInterface is often more maintainable than the package.
Normalize filenames at the edge. Even on v3.1, don't let user-supplied filenames be the only thing standing between an editor and a failed upload. If you have a form type or upload controller in front of Sulu, lowercasing the extension before handoff is cheap insurance and keeps you working if the package is ever dropped. This is especially relevant for any custom upload path that bypasses Sulu's own normalisation.
Per-collection rules. Sulu media collections are the natural place for policy — "press images keep original quality, marketing images get aggressive compression." If the bundle config is global only, wrap it: a Doctrine prePersist listener on Sulu\Bundle\MediaBundle\Entity\Media, or a decorator around the optimizer, can inspect the collection and adjust quality before optimization runs. Keep this thin; don't reimplement image processing.
Async for large assets. Synchronous optimization in the admin request is fine for a few MB but blocks editors and risks PHP timeouts on large TIFFs/PNGs. Pattern: upload normally, dispatch a Symfony Messenger message with the media ID, optimize in a worker, replace the file via StorageInterface, then invalidate Sulu's image-format cache for that media. This is the main reason to fork if the package is strictly synchronous.
Backfilling existing media. The bundle optimizes new uploads only. For an existing library, write a console command that pages through MediaRepository, resolves each file through sulu_media.storage, runs the same optimizer service, and writes back. Batch it, log before/after sizes, and invalidate caches at the end. This is destructive by definition — back up first.
CI/CD. Put binaries in the base image, not a post-deploy script. Add a functional test that calls MediaManagerInterface::save() with a fixture image and asserts the stored size is smaller than the source. Include an uppercase-extension fixture — the v3.1 fix exists precisely because nobody had that test. That catches missing binaries, version regressions, and misconfiguration in CI before editors do.
Thumbnails. Optimization applies to originals; Sulu's image formats are derived and cached separately. You get lower storage and faster thumbnail generation, but thumbnails themselves aren't optimized unless you also tune LiipImagine/Sulu image format filters. Decide which layer you're targeting.
.JPG/.PNG uploads threw UnsupportedImageFormat on earlier tags. Verify your locked version, and if you're stuck below 3.1, either patch/backport the change or normalise extensions before the media manager sees them. Note this is an upload failure, not a silent skip — editors see a hard error, which is at least diagnosable, but it looks like a Sulu bug rather than a bundle bug until you check -vvv logs.ignore_types semantics shifted in v3.1. Format detection and ignore_types handling both changed in the same release. If you set ignore_types on an older version, re-read your config and re-test the skipped formats after upgrading — a mime-string that previously matched may now be detected differently. Diff the bundle's config definition in DependencyInjection/Configuration.php across the upgrade rather than assuming compatibility.spatie/image-optimizer may be lower risk.upload_max_filesize, post_max_size, memory_limit, and max_execution_time govern the request before and during optimization. A 40 MB PNG that uploads fine can still OOM during processing.svgo is configured carefully.sulu_media.media_manager, order matters. Set decoration_priority explicitly instead of relying on load order.debug:container to see the actual decorated class, -vvv logs for the optimizer command, and exiftool/file on the stored asset to confirm what changed. For format-detection issues, log the detected mime type before the optimizer runs — that's where both the uppercase-extension bug and ignore_types mismatches surface.MediaManagerInterface — keep it the only place that knows about the package so removal later is a one-file change.How can I help you explore Laravel packages today?