ardavan/filament-file-explorer
Finder-style file manager for Filament v4 and v5, powered by Spatie Media Library, Livewire, and Tailwind. Browse, upload, and pick files with an explorer page, files table, and form picker.
spatie/laravel-medialibrary already wired up (migrations run, HasMedia trait on whatever model the explorer manages).
composer require ardavan/filament-file-explorer
php artisan vendor:publish --tag="filament-file-explorer-config"
php artisan migrate
admin or content panel rather than every panel:
->plugin(\Ardavan\FilamentFileExplorer\FilamentFileExplorerPlugin::make())
ardavanshamroshan.github.io/filament-file-explorer) for the plugin's option methods. The config will tell you more about the package's assumptions than any other file.SpatieMediaLibraryFileUpload form field — start by giving editors a browsing surface, then decide whether to tighten the integration.A quick sanity check before you build anything: create a throwaway panel, register the plugin, upload a file, and confirm it lands on the disk and model you expect. The folder-to-media mapping is the single thing worth validating on day one, because it drives everything else.
Treat the explorer as a shared library, not a per-model field. The value of a Finder UI is that the same asset can be browsed in one place and referenced in many. Attach HasMedia to a single MediaFolder-ish model (or whatever the package's default owner is) and let other models reference by media ID or path rather than re-uploading.
Panel-scoped registration for multi-panel apps. If you have separate admin and vendor panels, register the plugin only where it belongs, and lean on Filament's canAccess() on the page plus policies on the media model to gate who sees what. Folders are a natural permission boundary — map them to roles rather than trying to hide individual files.
Pair it with a picker field. The typical day-to-day workflow is: editor uploads/organises in the explorer page, then a form field selects from that library. Use a Select populated from the media query (with getOptionLabelFromRecordUsing for a thumbnail + filename), or a custom Filament field that opens the explorer in a modal. This keeps upload logic in one place and avoids duplicate media rows.
Configure the disk once, everywhere. Set the same disk name in config/filesystems.php, the package config, and media-library.disk_name. If you're on S3, verify the package respects visibility and temporary URLs — thumbnails break loudly otherwise.
Register conversions in one place. If you need thumbnails at specific sizes for the explorer grid, define them as a registerMediaConversions on the media model (or the package's configured model) and reference the conversion names in the config rather than hardcoding sizes in views.
Seed folders for repeatable environments. When your app has fixed taxonomy (e.g. products/, banners/, documents/legal/), seed them via a seeder or an artisan command so staging and production start with the same tree. Ad-hoc folder creation by editors is fine, but structural folders shouldn't be tribal knowledge.
Wrap it in a policy from day one. Even with 15 stars and zero dependents, this is a file-manager surface — deletion is destructive and irreversible-ish. Add a MediaPolicy with delete restricted to admins, and consider a soft-delete/trash approach if the package doesn't ship one.
composer.json, commit composer.lock, and skim the CHANGELOG before every minor bump. Filament plugin APIs churn between Filament majors — expect v4→v5 to be the first real break.folder column, a path convention, a separate model) is the thing most likely to diverge from your existing media usage. If you already have media rows with paths baked into collections, do a dry-run migration before pointing the explorer at production data.report.pdf upload twice in the same folder — Media Library renames by default, but the displayed name may not match what's on disk. Test with spaces, accents, and non-Latin characters early; slugifying or sanitising uploads is often necessary for S3/CDN sanity.FileUpload gives you ->acceptedFileTypes() and ->maxSize() out of the box; this package's validation is likely config-driven. Verify server-side enforcement — the browser-side accept attribute is not a security control. Add a MIME allowlist and an explicit max size before exposing it to non-admins.storage:link missing, wrong disk in config, or the media row's disk/directory columns disagreeing with the explorer's expected layout. SELECT disk, directory, file_name FROM media ORDER BY id DESC LIMIT 10; is your fastest diagnostic.content or you'll get unstyled grids in production builds. Check the docs for an "assets" or "theme" installation step and don't skip it.--tag=filament-file-explorer-views), and event/listener hooks around upload and delete. With a package this small, the maintainer's intended customisation story is probably config + published views, not a plugin architecture — plan accordingly.Media::query()." Keep your own logic out of package internals (no subclassing its Livewire components, no direct property access) so that swap stays a weekend, not a quarter.How can I help you explore Laravel packages today?