juniyasyos/filament-media-manager
A Filament media manager for browsing, uploading, and organizing files and folders through an intuitive interface. Manage images and media assets directly from your admin panel with a clean, responsive UI built for Laravel and Filament applications.
This package is a Filament panel plugin that puts a folder-based media browser (backed by spatie/laravel-medialibrary) into your admin UI, plus a form component for picking existing media when editing records.
Minimal install:
composer require juniyasyos/filament-media-manager
php artisan vendor:publish --tag="filament-media-manager-config"
php artisan vendor:publish --tag="filament-media-manager-migrations"
php artisan migrate
php artisan storage:link
Register it on the panel you want it in (app/Providers/Filament/AdminPanelProvider.php):
->plugin(FilamentMediaManagerPlugin::make())
Look at these first, in this order:
config/filament-media-manager.php — disk, accepted file types, base path, and the media model binding. Almost every "it doesn't work" report traces back here.Media model — confirm whether the package ships its own model or defers to Spatie's, because that determines where you add conversions.First use case: open the Media Manager page in the panel, create a folder, upload an image, then drop the package's media-picker field into an existing Resource form whose model uses Spatie's InteractsWithMedia. That end-to-end loop (upload → pick → render getFirstMediaUrl()) exercises disk config, the storage symlink, and the picker's state handling all at once — do it before wiring anything into production forms.
Prerequisites worth checking up front: Filament v3 (v4 is not guaranteed), PHP 8.1+, and a User model that implements FilamentUser if your panel is non-local — otherwise the page registers but nobody can reach it.
Attach selected media to a model. The picker gives you a media ID or path, not a file. The clean pattern is to keep the field as a non-persisted form input and move the media in a lifecycle hook, so you are not fighting Spatie's own media relationship:
MediaPicker::make('featured_media_id')
->label('Featured image')
->dehydrated(false)
->afterStateHydrated(fn ($component, $record) => $component->state(
$record?->getFirstMedia('featured')?->id
));
Then, in afterCreate / afterSave on the page (or a mutateFormDataBeforeSave that strips the key), copy the media onto the record's collection.
Collections over ad-hoc paths. Decide your collection names (featured, gallery, documents) and register conversions on the model, not in the package. The manager becomes the shared library; the model owns the rendering contract. This keeps you free to replace the UI later.
Multi-tenant / per-user folders. The directory shown is derived from the filesystem path, so tenancy is handled by scoping that path — either via the config base path or by overriding the page's directory resolution for the current tenant. Register the plugin per panel; for a tenant panel, give each tenant a subdirectory and reuse one Spatie Media model.
S3 or other non-local disks. Set the disk in config and verify the browser component can list it. Local disk is the well-trodden path; object storage works but you lose the cheap storage:link shortcut and need signed/temporary URLs configured on the Filament filesystem driver.
Gate it like any other page. Because it is a full page with delete and upload powers, wire it into your policy layer. Simplest version: FilamentMediaManagerPlugin::make()->navigationGroup('Content') plus a canView() check, or ->shouldRegisterNavigation(false) and link to it only from authorised contexts.
Compose with Relation Managers. For galleries and attachments, a relation manager or repeater whose field is the media picker scales better than one giant "attachments" collection, and it keeps the media table from becoming a single hot relationship.
3.0) does not follow the same scheme as v1.4.1. Read the actual diff on GitHub before upgrading, and pin the exact version in composer.json rather than using a floating constraint until the tag scheme is clarified.storage:link or disk mismatch, not the package. Confirm the file exists under storage/app/public/..., that APP_URL is correct, and that the config disk matches the disk the model was saved with.accepted_file_types or disk, run php artisan config:clear (and filament:optimize-clear if you optimise).upload_max_filesize / post_max_size, Livewire's temporary upload rules, and Filament's own maxSize(). A silent failure on large files usually means the middle layer.registerMediaConversions() and custom accessors there, then php artisan vendor:publish --force safely on upgrades.php artisan filament:assets so the page's JS matches the installed PHP version; a stale asset manifest produces an empty or inert file browser.$model->addMedia(...) outside Filament first — that tells you within a minute whether you are debugging the package or the media library.How can I help you explore Laravel packages today?