| Install | |
|---|---|
composer require georgemosesgroup/filament-media-library |
|
| Latest Version: | 1.2.5 |
| PHP: | ^8.1|^8.2|^8.3|^8.4 |
A powerful media library package for Filament with MediaPicker form component, drag & drop uploads, and full integration with FileManager.
| Package | Version |
|---|---|
| PHP | 8.1+ |
| Laravel | 10.x, 11.x, 12.x |
| Filament | 3.x, 4.x, 5.x |
composer require georgemosesgroup/filament-media-library
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:
Then rebuild your theme:
npm run build
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.
php artisan vendor:publish --tag="filament-media-library-config"
php artisan migrate
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.
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
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()
Config file: config/filament-media-library.php
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',
],
];
The package fully supports S3-compatible cloud storage including AWS S3 and DigitalOcean Spaces.
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',
],
],
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
Update your .env:
MEDIA_LIBRARY_DISK=do_spaces # or 's3' for AWS
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),
]);
}
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')
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();
});
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
// 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'])
// Single file (default)
MediaPicker::make('cover_id')
// Multiple files
MediaPicker::make('gallery_ids')
->multiple()
->maxFiles(20)
->minFiles(1)
MediaPicker::make('image_id')
->modalPosition('center') // 'center' or 'slide-over'
->modalWidth('3xl') // sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl
MediaPicker::make('image_id')
->directory('Uploads/{date}') // Auto folder structure
->autoCreateDirectory(true) // Create folders if not exist
->maxFileSize(10 * 1024 * 1024) // 10MB limit
MediaPicker::make('image_id')
->required()
->disabled()
->hidden(fn () => !auth()->user()->canUpload())
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:
In grid mode, media files have built-in players:
Video:
Audio:
Browse Mode (default) - Click "Browse Library" button
Upload Mode - Enable with ->allowUpload()
Single file: Stores integer ID
'cover_image_id' => 42
Multiple files: Stores JSON array of IDs
'gallery_ids' => [42, 43, 44]
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();
}
}
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(),
]),
];
}
The package automatically handles tenant isolation:
Tenant is resolved from (in order):
tenantFilament::getTenant()tenant_idfilament_tenant_idThis package uses the same database tables as FileManager:
file_folders - Folder structurefile_items - File recordsfile_tags - File tagsfile_versions - File versionsfile_shares - Shared linksFiles uploaded via MediaPicker appear in FileManager and vice versa.
# 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 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
After updating via composer, run:
composer update georgemosesgroup/filament-media-library
php artisan filament:assets
php artisan view:clear
When allowUpload() is enabled:
All components are fully responsive and work on mobile devices.
Check Laravel log for details:
tail -f storage/logs/laravel.log
Common issues:
upload_max_filesize in php.iniphp artisan cache:clearphp artisan filament:cache-componentsMIT License - see LICENSE file for details.