itskodinger/midia
Midia is a Laravel media manager with a built-in file browser for uploading, organizing, and managing images and files. It supports configurable storage disks, image handling, and quick integration into Laravel apps.
Check compatibility before anything else. The last tagged release is from June 2019, so the package targets Laravel 5.5–5.8 and PHP 7.x. Run it on a feat/midia-spike branch on your actual Laravel version first — do not assume Composer will resolve cleanly against Laravel 10/11 (illuminate/* constraints and the Stringable/helper changes are common breakage points).
Minimal install:
composer require itskodinger/midia
php artisan vendor:publish --provider="Itskodinger\Midia\MidiaServiceProvider"
php artisan storage:link
If auto-discovery is unavailable (older Laravel), add the provider to config/app.php and, if the README documents one, the facade alias.
Where to look first, in order:
config/midia.php) — this is where the storage disk, upload path, route prefix, and middleware live. Almost every day-to-day question is answered here.php artisan route:list --path=midia — confirms the route prefix, the controller, and whether auth middleware is attached (it usually is not by default).resources/views and routes/ directory under vendor/itskodinger/midia/ — the README for a 2019 package is often thinner than the source, and the routes file tells you the exact endpoint names to call from your own JS.php artisan vendor:publish --tag=midia.views (or the equivalent tag the provider exposes) if you need to restyle the UI.First use case: a drop-in media library so content editors can browse and upload images without you building an admin CRUD screen. Point the config at your public disk, log in, hit /midia, upload a file, and confirm it lands where the config says. Then verify you can render it in a Blade view using whatever path helper the README provides — do this before wiring it into a real form.
Store the relative path, not the URL. The single most important integration decision: persist the disk-relative path (media/2024/06/photo.jpg) in your database column, and resolve to a full URL at render time through Storage::disk(config('midia.disk'))->url($path). This keeps you portable if you later move from local disk to S3 — a real risk given how old the package is and how likely you are to outgrow it.
Gate the routes with your own middleware. In config/midia.php, set the middleware array to something like ['web', 'auth', 'can:manage-media']. This is non-negotiable on any non-local environment; the default is often just web, which means an unauthenticated visitor can upload and delete files.
Embed as a picker, not just a page. The common editorial pattern is a "Choose image" button next to a text input. Open /midia in a modal/iframe, and have the media manager post the selected path back to the parent window (or, if the package doesn't support a callback, link out in a new tab and let the editor paste the path). If you need a smoother flow, wrap the package's index route in your own controller and pass a callback query param your view's JS reads — but only after reading the vendored views to see what hooks already exist.
Use it as an upload backend for a WYSIWYG. Inspect the upload route in vendor/.../routes/ and see whether it returns JSON. If it does, TinyMCE/CKEditor's images_upload_handler can POST a FormData straight to it and receive a URL back. This is often the highest-leverage use of a package like this and requires no view customization at all.
Compose with your own model layer. Don't let the package own your media metadata. Keep a media table (path, disk, mime, size, alt text, uploaded_by) and either listen for the package's upload event if one exists, or sync on save via a small service class. That way, if the package dies (see Gotchas), your data model outlives it and you can swap the UI.
Custom disks for production. Set midia.disk to an S3/R2 disk in config/filesystems.php and confirm the package uses Laravel's Storage facade (not move_uploaded_file/file_put_contents). If it bypasses the filesystem abstraction, you're locked to local disk — find this out on day one, not at deploy time.
composer.json, and budget for forking it into packages/midia if you need to patch it.storage:link is silent when it fails. If uploads succeed but images 404, check that public/storage exists and points at storage/app/public, and that the configured disk root actually matches. This is the #1 "it's broken" report.composer update is easy to forget. Also be aware it may reference a Mix-generated mix-manifest.json — on Vite-based Laravel apps that file won't exist and the UI will render unstyled.mimes:/max:, and regenerate filenames.php artisan config:cache traps. Because almost all behavior is read from config/midia.php, a stale config cache will make you debug a change that did apply. Always php artisan config:clear when tuning.vendor/ to read directly.How can I help you explore Laravel packages today?