luketowers/oc-tinypng-plugin
An October CMS plugin that integrates the TinyPNG API to automatically compress and optimize PNG and JPEG images, reducing file sizes while preserving visual quality. Offers configurable resizing and simple setup for faster-loading, better-performing websites.
This is a Winter CMS plugin, not a standalone Laravel package. It hooks into Winter's file/media pipeline to push uploads through the TinyPNG API. Add it to a Winter project, not a vanilla Laravel app.
composer require luketowers/oc-tinypng-plugin
php artisan winter:up # October CMS 1.x projects: php artisan october:up
Alternatively install from Backend → Settings → Updates & Plugins and search the marketplace. After install, the plugin registers itself via its Plugin.php.
Where to look first (small codebase — read it before trusting it):
Plugin.php — see what events/models it extends (System\Models\File, Media Library events, console commands).models/ and updates/ — the settings model and the migration that stores your API key.console/ (if present) — one-off/backfill commands; discover with php artisan list | grep -i tiny.lang/ — confirms the exact backend settings label.Configure the key: Backend → Settings → TinyPNG (or Misc), paste a key from https://tinypng.com/developers. Free tier is ~500 compressions/month.
First use case: upload a JPEG through the Media Manager, confirm the file size drops, and confirm the settings page/API call succeeds. Then run the plugin's console command to backfill existing media.
Transparent optimization on upload. The primary pattern is zero-code: any model using attachOne/attachMany with System\Models\File should get optimized if the plugin listens to File save events. Verify by checking Plugin.php for File::extend(...) or an Event::listen('...upload...').
Backfill + scheduled sweep. New uploads are easy; the long tail is everything already in storage/app/uploads or the media library. Wrap the plugin's console command in the scheduler so files uploaded during a quota outage get caught later:
// Plugin.php register()
$schedule->command('tinypng:optimize')->weekly()->withoutOverlapping();
Programmatic use in your own upload flow. If the plugin exposes an optimizer service, resolve it rather than reimplementing the HTTP call. Prefer queueing so a slow TinyPNG round-trip doesn't block the request:
// app or a custom plugin
dispatch(function () use ($file) {
app(\Luketowers\TinyPng\Classes\Optimizer::class)->optimize($file);
})->onQueue('images');
(Confirm the class name in the plugin's classes/ or models/ directory — it is a small package, so read the constructor signature.)
Pair with a resizer, not instead of one. Generate responsive derivatives locally (Intervention/| resize), then optimize only the source uploads. Optimizing every derivative multiplies quota usage by the number of breakpoints.
Environment separation. If the settings model supports env(), point it at TINYPNG_API_KEY so staging and production don't share a 500/month budget. Otherwise add a deploy step that seeds the setting row, and treat the settings table as required configuration.
storage/app/uploads remain. Clear them (php artisan cache:clear, delete the derived folder) or you'll see no visual change.oc- prefix, Winter target. Verify the composer.json platform requirement matches your Winter version; October CMS 3.x and Winter 1.x have diverged enough that hooks may not fire. Read Plugin.php before upgrading a major.debug => true in config/app.php, then tail storage/logs/system.log. If the plugin logs under its own channel, grep for tinypng.$this->app->bind(...) in your own plugin's register() to add hashing, logging, or a dry-run mode rather than editing vendor code.composer.json. It's small enough to fork comfortably if the TinyPNG API or Winter's file events move under you.How can I help you explore Laravel packages today?