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

Media Manager Laravel Package

optix/media-manager

Optix Media Manager is a Laravel package for uploading, browsing, organizing, and managing files and images. It provides a ready-to-use file manager UI with folders, search, thumbnails, and storage support, making media handling easy to integrate into any Laravel application.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Check your Laravel and PHP versions first

v0.5.0 adds Laravel 8.0 support and drops PHP 7.2. So the supported envelope is now roughly PHP 7.3+ on Laravel 8.x. If you're on PHP 7.2, pin to ^0.4; if you're on Laravel 9+, this package is still not for you (see Gotchas).

composer require optix/media-manager:^0.5
php artisan vendor:publish --provider="Optix\Media\MediaServiceProvider"

That should publish config/media-manager.php (and any views/assets). Verify with php artisan vendor:publish listing the provider's tags if the config doesn't appear.

2. Point it at a disk and link storage

Make sure the disk you intend to use exists in config/filesystems.php, then reference it in config/media-manager.php (typically a disk key, defaulting to public). If using the public disk:

php artisan storage:link

The package serves and manipulates files through your Laravel disk abstraction, so the disk must be readable and — for generated image derivatives — writable by the web process. On Laravel 8 this is Flysystem 2, so Storage::url() behaviour differs from older Laravel versions; verify the generated URLs point where you expect.

3. Guard the manager route

The package exposes a file-manager UI (commonly /media-manager). Before you touch anything else, add auth middleware in the published config so uploads/deletes aren't public:

'middleware' => ['web', 'auth'],

4. First use case

Visit the manager, upload an image, and copy its stored path. Render it in Blade through the package's URL builder (name varies by version — check the README for MediaManager::url()/media_url()):

<img src="{{ media_url('blog/covers/hero.jpg', ['w' => 800, 'fit' => 'crop']) }}">

That's the whole loop: upload in the UI → store on a disk → generate a manipulated URL on demand.

Implementation Patterns

Wrap URL generation in one place. Don't scatter hard-coded /storage/... paths or query strings through views. Create a small helper or Blade component that delegates to the package:

{{-- resources/views/components/media-image.blade.php --}}
@props(['path', 'size' => 'medium'])
<img
    src="{{ media_url($path, config("media-manager.sizes.{$size}")) }}"
    {{ $attributes }}
>

Define named sizes in config rather than magic params. A sizes array (thumb, card, hero) prevents each developer from inventing their own w/h/fit combinations, and makes swapping the media backend later a one-file change.

Use srcset for responsive output. The URL builder is stateless, so generating multiple derivatives is cheap in the template and images are generated lazily on first request:

<img srcset="
    {{ media_url($path, ['w' => 400]) }} 400w,
    {{ media_url($path, ['w' => 800]) }} 800w,
    {{ media_url($path, ['w' => 1600]) }} 1600w"
    sizes="(max-width: 600px) 400px, 800px" src="{{ media_url($path, ['w' => 800]) }}">

Separate admin storage from public serving. Store uploads on a private disk if they're user-submitted; expose only the serving route with explicit path validation. Keep the file-manager UI on a route group with auth + a policy/gate (can:manage-media) so editors can manage assets without gaining broader admin access.

WYSIWYG / editor integration. The package is typically used as a picker for TinyMCE/CKEditor. Wire the editor's file-browser callback to the manager route, and have it return the stored path (not an absolute disk path) so the same value works with media_url().

Programmatic uploads. For bulk imports or API endpoints, write with Storage::disk($disk)->putFileAs(...) and then reference the returned relative path through the same URL helper. This keeps non-UI uploads indistinguishable from UI uploads downstream. Note Flysystem 2 (Laravel 8) returns a path string here rather than a bool — don't write if (! Storage::put(...)) checks, assert on the returned path.

Cache and CDN. Generated derivatives should be served with long Cache-Control headers and a stable URL. If you front the site with a CDN, purge the media prefix on deploy, and add a ?v= or filename hash if you overwrite files in place.

Testing. Assert that media_url() returns a path scoped to the configured disk, and add an integration test that requests a manipulated URL and asserts a 200 plus an image/* content type. That catches missing GD/Imagick extensions and unwritable cache directories before production. Also add a test that pins your PHP/Laravel constraint — the 0.4 → 0.5 bump shows version support moves in this package, and you want the failure to surface in CI, not on deploy.

Gotchas and Tips

Maintenance risk is still the headline, but read the direction of travel. v0.5.0 (Laravel 8 support, PHP 7.2 dropped) is the first release since October 2020 and confirms the package is alive but conservative. It still predates Laravel 9's Flysystem 3 upgrade, which changed Storage::url(), adapter internals, and how Glide/Intervention read from disks. So: Laravel 8 is the ceiling until proven otherwise. Test the serving route and image manipulation specifically on whatever Laravel version you're on, and budget time to fork or pin.

Pin the version explicitly. composer require optix/media-manager will float. With a single-maintainer package that jumps PHP minimums between minor releases, constrain to ^0.5 and let Renovate/Dependabot open a PR you can test rather than discovering the bump on deploy.

PHP minimum moved to 7.3 in v0.5.0. The 0.4 → 0.5 upgrade is a breaking change for anyone on 7.2. Check php -v on every environment (including your queue workers and CI image) before bumping — Composer failing at install time is the good outcome; a mismatch between local and production PHP is the bad one.

The route is public by default. This is the most common security mistake: an unauthenticated /media-manager accepts uploads and deletes. Add middleware immediately after publishing.

Directory permissions bite first. "Images not showing" is almost always the derivative cache directory not existing or not being writable by www-data. Check storage/app/public permissions and the package's configured cache path before debugging routing.

Path handling and traversal. Audit the serving route's handling of ../ and encoded traversal in the path segment, and confirm it restricts reads to the configured disk root. Older packages sometimes pass the raw path straight to the filesystem adapter.

Image driver dependencies. Glide/Intervention needs gd or imagick; WebP support depends on the extension build and driver version. If uploads succeed but derivatives 500, check php -m and storage/logs/laravel.log first. Dropping PHP 7.2 support doesn't change driver requirements, so this isn't fixed by the upgrade.

PHP limits vs. package limits. The package's max_file_size/MIME config is only half the story — upload_max_filesize and post_max_size in php.ini (and Nginx client_max_body_size) will silently reject larger uploads. Align all three.

Config caching quirks. php artisan config:cache freezes the published config. Any env() you add inside config/media-manager.php will return null in cached production configs. Prefer config keys referencing other config values.

Deploy wipes derivatives. If your deploy replaces public/ or clears caches, derivative images vanish and regenerate on first request — fine for low traffic, a thundering herd on a popular page. Pre-warm the top N images in a deploy step, or persist the cache directory across releases. Since releases are rare, your deploy pipeline is the thing most likely to break you, not the package.

Debugging checklist, in order: composer show optix/media-manager (which version did I actually get, and what PHP does it require?), php artisan route:list | grep media (is the route registered and middleware right?), inspect the exact URL the helper returns, tail storage/logs/laravel.log, then verify the file exists with Storage::disk($disk)->exists($path) in tinker. Most "broken image" reports resolve at one of those steps.

Extension points. If the URL builder doesn't fit, subclass/wrap the MediaManager class or bind your own implementation in a service provider — this keeps a future migration to spatie/laravel-medialibrary or a custom Intervention controller limited to your wrapper rather than every view. Given the package's release cadence, assume you will eventually own this code.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
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