georgemosesgroup/filament-media-library
| Install | |
|---|---|
composer require georgemosesgroup/filament-media-library |
|
| Latest Version: | 1.2.5 |
| PHP: | ^8.1|^8.2|^8.3|^8.4 |
| License: | MIT |
| Last Updated: | Jan 30, 2026 |
| Links: | GitHub · Packagist |
Filament Media Library
A powerful media library package for Filament with MediaPicker form component, drag & drop uploads, and full integration with FileManager.
Requirements
| Package | Version |
|---|---|
| PHP | 8.1+ |
| Laravel | 10.x, 11.x, 12.x |
| Filament | 3.x, 4.x, 5.x |
Features
- Media Library Page - Full standalone file manager in navigation
- MediaPicker Form Component - Select files from library or upload new ones
- Two Modes - Browse-only (default) or Upload mode
- Browse Library Modal - Full file browser with folder navigation
- Single & Multiple Selection - Support for cover images and galleries
- Gallery Grid Layout - Unified container with customizable columns and height
- Interactive Media Players - Built-in video and audio players in grid mode
- Auto Directory Structure - Automatically creates folder hierarchy based on resource name
- Multi-tenancy Support - Full tenant isolation out of the box
- Filament Plugin - Easy registration with customizable navigation
Installation
composer require georgemosesgroup/filament-media-library
Quick Install (Recommended)
Run the install command to automatically configure everything:
# Basic installation (local storage)
php artisan filament-media-library:install
# With DigitalOcean Spaces
php artisan filament-media-library:install --storage=do_spaces
# With AWS S3
php artisan filament-media-library:install --storage=s3
This will:
- Publish the config file
- Run migrations
- Configure storage (DO Spaces/S3 if selected)
- Configure your Filament theme CSS for Tailwind
Then rebuild your theme:
npm run build
Manual Installation
1. Register Plugin
Add the plugin to your Filament panel in AdminPanelProvider.php:
use Alura\FilamentMediaLibrary\FilamentMediaLibraryPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugins([
FilamentMediaLibraryPlugin::make(),
]);
}
This automatically adds the Media Library page to your navigation.
2. Publish Config (Optional)
php artisan vendor:publish --tag="filament-media-library-config"
3. Run Migrations
php artisan migrate
4. Publish Assets
The package includes its own CSS for hover effects and animations. Publish the assets:
php artisan filament:assets
Note: This step is required after installation or updating the package. The CSS is automatically registered with Filament's asset system.
5. Configure Custom Theme (Optional - for Media Library Page)
If you're using the Media Library page (not just MediaPicker), add the package views to your Filament theme CSS (resources/css/filament/admin/theme.css):
@source '../../../vendor/georgemosesgroup/filament-media-library/resources/views/**/*';
Then rebuild your theme:
npm run build
Plugin Options
Customize the Media Library page:
FilamentMediaLibraryPlugin::make()
->navigationGroup('Content') // Group in navigation
->navigationSort(10) // Sort order
->navigationIcon('heroicon-o-folder') // Custom icon
->navigationLabel('Files') // Custom label
Disable the page (use only MediaPicker component):
FilamentMediaLibraryPlugin::make()
->disableMediaLibraryPage()
Configuration
Config file: config/filament-media-library.php
Key Settings
return [
// Storage disk
'disk' => env('MEDIA_LIBRARY_DISK', 'public'),
// Upload limits
'upload' => [
'max_file_size' => 100 * 1024 * 1024, // 100MB
'max_files_per_upload' => 50,
],
// Multi-tenancy
'multi_tenancy' => [
'enabled' => true,
'tenant_column' => 'tenant_id',
],
// Modal appearance
'picker' => [
'default_position' => 'slide-over', // 'center' or 'slide-over'
'default_width' => 'md',
],
];
Cloud Storage (S3 / DigitalOcean Spaces)
The package fully supports S3-compatible cloud storage including AWS S3 and DigitalOcean Spaces.
1. Configure Filesystem Disk
Add to config/filesystems.php:
'disks' => [
// ... other disks
// DigitalOcean Spaces
'do_spaces' => [
'driver' => 's3',
'key' => env('DO_SPACES_KEY'),
'secret' => env('DO_SPACES_SECRET'),
'region' => env('DO_SPACES_REGION', 'sfo3'),
'bucket' => env('DO_SPACES_BUCKET'),
'url' => env('DO_SPACES_URL'),
'endpoint' => env('DO_SPACES_ENDPOINT'),
'use_path_style_endpoint' => false,
'visibility' => 'public',
],
// AWS S3
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'visibility' => 'public',
],
],
2. Environment Variables
For DigitalOcean Spaces:
DO_SPACES_KEY=your-key
DO_SPACES_SECRET=your-secret
DO_SPACES_REGION=sfo3
DO_SPACES_BUCKET=your-bucket-name
DO_SPACES_URL=https://your-bucket-name.sfo3.digitaloceanspaces.com
DO_SPACES_ENDPOINT=https://sfo3.digitaloceanspaces.com
MEDIA_LIBRARY_DISK=do_spaces
For AWS S3:
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=your-bucket-name
AWS_URL=https://your-bucket-name.s3.amazonaws.com
MEDIA_LIBRARY_DISK=s3
3. Set Media Library Disk
Update your .env:
MEDIA_LIBRARY_DISK=do_spaces # or 's3' for AWS
Features
- Automatic thumbnail generation - Works seamlessly with cloud storage
- Public URLs - Files are publicly accessible via CDN
- Visibility control - Set 'public' or 'private' visibility per file
- Temporary URLs - Private files use signed temporary URLs (S3 feature)
Usage
Basic Usage (Browse Mode - Default)
By default, MediaPicker shows a "Browse Library" button to select from existing files:
use Alura\FilamentMediaLibrary\Forms\Components\MediaPicker;
public static function form(Form $form): Form
{
return $form->schema([
// Single image - browse from library
MediaPicker::make('cover_image_id')
->label('Cover Image')
->images(),
// Multiple images - browse from library
MediaPicker::make('gallery_ids')
->label('Gallery')
->images()
->multiple()
->maxFiles(10),
]);
}
Upload Mode
Enable drag & drop upload with allowUpload():
MediaPicker::make('cover_image_id')
->label('Cover Image')
->images()
->allowUpload() // Enable drag & drop upload
->directory('Products/{record_id}/Cover')
Model Setup
Minimum required:
class Product extends Model
{
protected $fillable = [
'name',
'cover_image_id', // integer - single file
'gallery_ids', // json - multiple files
];
protected function casts(): array
{
return [
'gallery_ids' => 'array', // Required for multiple files
];
}
}
Migration:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->foreignId('cover_image_id')->nullable()->constrained('file_items')->nullOnDelete();
$table->json('gallery_ids')->nullable();
$table->timestamps();
});
Auto Directory Structure
Automatically organize uploads into folders based on resource:
MediaPicker::make('cover_image_id')
->images()
->directory('Products/{record_id}/Cover')
Available placeholders:
| Placeholder | Description | Example |
|---|---|---|
{resource} |
Resource name | Products |
{record_id} |
Record ID | 123 |
{field} |
Field name | cover_image_id |
{date} |
Current date | 2026-01-28 |
{year} |
Current year | 2026 |
{month} |
Current month | 01 |
{tenant_id} |
Tenant ID | 1 |
Example folder structure:
Blog Posts/
├── 1/
│ ├── Cover/
│ │ └── image1.jpg
│ └── Gallery/
│ ├── photo1.jpg
│ └── photo2.jpg
└── 2/
└── Cover/
└── image2.jpg
Component Options
File Type Filters
// Only images
MediaPicker::make('image_id')->images()
// Only videos
MediaPicker::make('video_id')->videos()
// Only documents
MediaPicker::make('document_id')->documents()
// Custom mime types
MediaPicker::make('file_id')->acceptedTypes(['application/pdf', 'image/png'])
Selection Mode
// Single file (default)
MediaPicker::make('cover_id')
// Multiple files
MediaPicker::make('gallery_ids')
->multiple()
->maxFiles(20)
->minFiles(1)
Modal Customization
MediaPicker::make('image_id')
->modalPosition('center') // 'center' or 'slide-over'
->modalWidth('3xl') // sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl
Upload Settings
MediaPicker::make('image_id')
->directory('Uploads/{date}') // Auto folder structure
->autoCreateDirectory(true) // Create folders if not exist
->maxFileSize(10 * 1024 * 1024) // 10MB limit
Visibility & State
MediaPicker::make('image_id')
->required()
->disabled()
->hidden(fn () => !auth()->user()->canUpload())
Gallery Layout (Grid Mode)
Display multiple files in a customizable grid layout:
// Preset gallery layouts with configurable parameters
MediaPicker::make('gallery_ids')
->multiple()
->gridGallery() // Default: 3 columns, 120px height, cover
->gridGallery(4) // 4 columns
->gridGallery(4, '150px') // 4 columns, 150px height
->gridGallery(4, '150px', 'contain') // Full customization
// Other presets
MediaPicker::make('gallery_ids')
->multiple()
->compactGallery() // 2 columns, 150px height
->thumbnailGallery() // 4 columns, 100px height
->thumbnailGallery(6, '80px') // 6 columns, 80px height
// Manual configuration
MediaPicker::make('gallery_ids')
->multiple()
->previewColumns(4) // Number of columns (1-6)
->previewMaxHeight('150px') // Height of each item
->previewImageFit('cover') // 'cover', 'contain', or 'fill'
Grid Mode Features:
- Unified container with files and "Add" button together
- Drag & drop directly onto the grid area with prominent overlay
- Interactive video player with play/pause
- Interactive audio player with purple gradient background
- Hover effects on cards with ring highlight
- Remove button appears on hover (red on hover)
- Smooth animations and transitions
Interactive Media Players
In grid mode, media files have built-in players:
Video:
- Click play button to start video
- Native controls appear (play, pause, progress, volume, fullscreen)
- Thumbnail shown when paused
Audio:
- Purple gradient background
- Click to play/pause
- Shows filename
How It Works
Two Modes
-
Browse Mode (default) - Click "Browse Library" button
- Opens modal with full file browser
- Navigate folders, search files
- Select existing files from library
-
Upload Mode - Enable with
->allowUpload()- Shows drag & drop zone
- Files upload immediately
- Stored in configured directory
- ID saved to form field
Data Storage
Single file: Stores integer ID
'cover_image_id' => 42
Multiple files: Stores JSON array of IDs
'gallery_ids' => [42, 43, 44]
Optional: Helper Methods
Add these to your model for convenient access:
class Product extends Model
{
// ... fillable and casts ...
// Relationship for eager loading
public function coverImage(): BelongsTo
{
return $this->belongsTo(FileItem::class, 'cover_image_id');
}
// Get cover URL
public function getCoverUrl(): ?string
{
return $this->coverImage?->getUrl();
}
// Get gallery images collection
public function getGalleryImages()
{
if (empty($this->gallery_ids)) {
return collect();
}
return FileItem::whereIn('id', $this->gallery_ids)->get();
}
// Get gallery URLs array
public function getGalleryUrls(): array
{
return $this->getGalleryImages()
->map(fn($img) => $img->getUrl())
->toArray();
}
}
API Usage (Frontend)
Get file data for API responses:
// In API Resource or Controller
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'cover_image' => $this->coverImage ? [
'id' => $this->coverImage->id,
'url' => $this->coverImage->getUrl(),
'thumbnail' => $this->coverImage->getThumbnailUrl(),
] : null,
'gallery' => $this->getGalleryImages()->map(fn($img) => [
'id' => $img->id,
'url' => $img->getUrl(),
'thumbnail' => $img->getThumbnailUrl(),
]),
];
}
Multi-tenancy
The package automatically handles tenant isolation:
- All files are scoped to current tenant
- Folder structure is tenant-specific
- Users can only see their tenant's files
Tenant is resolved from (in order):
- Container-bound
tenant - Filament
Filament::getTenant() - Authenticated user's
tenant_id - Session
filament_tenant_id
Synchronization with FileManager
This package uses the same database tables as FileManager:
file_folders- Folder structurefile_items- File recordsfile_tags- File tagsfile_versions- File versionsfile_shares- Shared links
Files uploaded via MediaPicker appear in FileManager and vice versa.
Artisan Commands
Install Command
# Basic installation
php artisan filament-media-library:install
# With DigitalOcean Spaces storage
php artisan filament-media-library:install --storage=do_spaces
# With AWS S3 storage
php artisan filament-media-library:install --storage=s3
# Skip theme configuration
php artisan filament-media-library:install --skip-theme
Migrate Storage Command
Migrate files between storage disks (e.g., local to cloud):
# Dry run (preview what will be migrated)
php artisan media-library:migrate-storage --from=public --to=do_spaces --dry-run
# Actual migration
php artisan media-library:migrate-storage --from=public --to=do_spaces
# Delete source files after migration
php artisan media-library:migrate-storage --from=public --to=do_spaces --delete-source
Updating the Package
After updating via composer, run:
composer update georgemosesgroup/filament-media-library
php artisan filament:assets
php artisan view:clear
UI/UX Features
Drag & Drop Upload
When allowUpload() is enabled:
- Clear "Drop to upload" overlay when dragging files
- Backdrop blur effect for better visibility
- Prominent border highlight
Card Hover Effects
- Ring highlight on card hover
- Remove button hidden by default, appears on hover
- Remove button turns red when hovered
- Subtle overlay on image cards
Upload Progress
- Animated progress bar with glow effect
- Shimmer animation during upload
- Success checkmark with green glow
- Error state with retry button
Responsive Design
All components are fully responsive and work on mobile devices.
Troubleshooting
Upload returns 500 error
Check Laravel log for details:
tail -f storage/logs/laravel.log
Common issues:
- tenant_id NULL - User not authenticated or tenant not resolved
- Permission denied - Check storage folder permissions
- File too large - Increase
upload_max_filesizein php.ini
Files not showing
- Clear cache:
php artisan cache:clear - Check tenant scope is correct
- Verify files exist in database
Modal not opening
- Check browser console for JS errors
- Ensure Alpine.js is loaded
- Clear Filament cache:
php artisan filament:cache-components
License
MIT License - see LICENSE file for details.