PHPackages                             georgemosesgroup/filament-media-library - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. georgemosesgroup/filament-media-library

ActiveLibrary[Admin Panels](/categories/admin)

georgemosesgroup/filament-media-library
=======================================

A powerful media library package for Filament v3/v4/v5+ with MediaPicker form component, drag &amp; drop uploads, folder management, and built-in responsive thumbnail generation

1.3.0(2mo ago)181—7.1%MITBladePHP ^8.1|^8.2|^8.3|^8.4

Since Jan 28Pushed 2mo agoCompare

[ Source](https://github.com/georgemosesgroup/FilamentMediaLibrary)[ Packagist](https://packagist.org/packages/georgemosesgroup/filament-media-library)[ Docs](https://github.com/georgemosesgroup/FilamentMediaLibrary)[ RSS](/packages/georgemosesgroup-filament-media-library/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (12)Versions (25)Used By (0)

Filament Media Library
======================

[](#filament-media-library)

A powerful media library package for Filament with MediaPicker form component, drag &amp; drop uploads, and full integration with FileManager.

Requirements
------------

[](#requirements)

PackageVersionPHP8.1+Laravel10.x, 11.x, 12.xFilament3.x, 4.x, 5.xFeatures
--------

[](#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 &amp; 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
------------

[](#installation)

```
composer require georgemosesgroup/filament-media-library
```

### Quick Install (Recommended)

[](#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

[](#manual-installation)

#### 1. Register Plugin

[](#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)

[](#2-publish-config-optional)

```
php artisan vendor:publish --tag="filament-media-library-config"
```

#### 3. Run Migrations

[](#3-run-migrations)

```
php artisan migrate
```

#### 4. Publish Assets

[](#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)

[](#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

[](#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
-------------

[](#configuration)

Config file: `config/filament-media-library.php`

### Key Settings

[](#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)

[](#cloud-storage-s3--digitalocean-spaces)

The package fully supports S3-compatible cloud storage including AWS S3 and DigitalOcean Spaces.

#### 1. Configure Filesystem Disk

[](#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

[](#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

[](#3-set-media-library-disk)

Update your `.env`:

```
MEDIA_LIBRARY_DISK=do_spaces  # or 's3' for AWS
```

#### Features

[](#features-1)

- **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
-----

[](#usage)

### Basic Usage (Browse Mode - Default)

[](#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

[](#upload-mode)

Enable drag &amp; 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

[](#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

[](#auto-directory-structure)

Automatically organize uploads into folders based on resource:

```
MediaPicker::make('cover_image_id')
    ->images()
    ->directory('Products/{record_id}/Cover')
```

**Available placeholders:**

PlaceholderDescriptionExample`{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
-----------------

[](#component-options)

### File Type Filters

[](#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

[](#selection-mode)

```
// Single file (default)
MediaPicker::make('cover_id')

// Multiple files
MediaPicker::make('gallery_ids')
    ->multiple()
    ->maxFiles(20)
    ->minFiles(1)
```

### Modal Customization

[](#modal-customization)

```
MediaPicker::make('image_id')
    ->modalPosition('center')     // 'center' or 'slide-over'
    ->modalWidth('3xl')           // sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl
```

### Upload Settings

[](#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 &amp; State

[](#visibility--state)

```
MediaPicker::make('image_id')
    ->required()
    ->disabled()
    ->hidden(fn () => !auth()->user()->canUpload())
```

### Gallery Layout (Grid Mode)

[](#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 &amp; 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

[](#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
------------

[](#how-it-works)

### Two Modes

[](#two-modes)

1. **Browse Mode** (default) - Click "Browse Library" button

    - Opens modal with full file browser
    - Navigate folders, search files
    - Select existing files from library
2. **Upload Mode** - Enable with `->allowUpload()`

    - Shows drag &amp; drop zone
    - Files upload immediately
    - Stored in configured directory
    - ID saved to form field

### Data Storage

[](#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
------------------------

[](#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)
--------------------

[](#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
-------------

[](#multi-tenancy)

The package automatically handles tenant isolation:

1. All files are scoped to current tenant
2. Folder structure is tenant-specific
3. Users can only see their tenant's files

Tenant is resolved from (in order):

1. Container-bound `tenant`
2. Filament `Filament::getTenant()`
3. Authenticated user's `tenant_id`
4. Session `filament_tenant_id`

Synchronization with FileManager
--------------------------------

[](#synchronization-with-filemanager)

This package uses the same database tables as FileManager:

- `file_folders` - Folder structure
- `file_items` - File records
- `file_tags` - File tags
- `file_versions` - File versions
- `file_shares` - Shared links

Files uploaded via MediaPicker appear in FileManager and vice versa.

Artisan Commands
----------------

[](#artisan-commands)

### Install Command

[](#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-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
```

Thumbnails
----------

[](#thumbnails)

The package generates two layers of thumbnails out of the box:

1. **Admin preview** — a single 300×300 thumbnail stored in the `thumbnail_path` column on `media_items` and used in the Filament admin grid. Generated synchronously on upload.
2. **Responsive thumbnails** — a configurable set of widths stored under `{thumbs_path}/{media_id}/{size}/{filename}.{format}`. Generated asynchronously by `GenerateThumbnailsJob`, intended for the front-end. Driver is selected automatically (Imagick → GD → noop).

### Configuration

[](#configuration-1)

```
// config/filament-media-library.php
'thumbnails' => [
    'enabled' => true,

    // Run inline instead of pushing to the queue (handy in tests).
    'sync' => env('MEDIA_THUMBS_SYNC', false),

    'queue' => [
        'connection' => env('MEDIA_THUMBS_QUEUE_CONNECTION'), // null = default
        'name' => env('MEDIA_THUMBS_QUEUE_NAME', 'default'),
    ],

    'driver' => env('MEDIA_THUMBS_DRIVER', 'auto'), // auto | imagick | gd

    'thumbs_path' => env('MEDIA_THUMBS_PATH', 'thumbs'),
    'sizes' => [1920, 1440, 1024, 768, 480, 320],
    'format' => env('MEDIA_THUMBS_FORMAT', 'webp'), // webp | jpg | avif
    'fallback_format' => 'jpg',
    'quality' => 80,
    'preserve_aspect_ratio' => true,
],
```

### API on `MediaItem`

[](#api-on-mediaitem)

```
$item->thumbUrl(1024);                  // URL for one size, or null
$item->thumbUrl(1024, 'jpg');           // override format
$item->thumbnails();                    // [1920 => url, 1440 => url, ...]
$item->getPreview(1024);                // best fit for a target width
$item->hasThumbnails();                 // bool — any responsive thumb on disk
$item->hasThumbnails(1024);             // bool — specific size
```

`getThumbnailUrl()` (legacy admin preview) and the `thumbnail_path` column continue to work as before.

### Driver Selection

[](#driver-selection)

DriverWhen usedimagick`extension_loaded('imagick')` and format supportedgdimagick missing, gd availablenoopboth missing — logs a warning, returns no thumbsSizes larger than the source width are skipped automatically. SVG and non-image items are also skipped.

### Regenerating Thumbnails

[](#regenerating-thumbnails)

```
# Regenerate everything (default)
php artisan media-library:regenerate-thumbnails

# Specific item
php artisan media-library:regenerate-thumbnails --id=123

# Force-redo even when thumbs already exist
php artisan media-library:regenerate-thumbnails --force

# Only items that have no thumbs yet
php artisan media-library:regenerate-thumbnails --missing
```

### Migration from Custom Observer

[](#migration-from-custom-observer)

If your application previously implemented its own `ThumbnailGenerator` + `MediaItemObserver` to produce responsive thumbs, you can drop them after upgrading to v1.3 — the package now handles this end to end. Update consumer code that reads paths to use `$item->thumbUrl($size)` instead of building paths by hand.

Updating the Package
--------------------

[](#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
--------------

[](#uiux-features)

### Drag &amp; Drop Upload

[](#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

[](#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

[](#upload-progress)

- Animated progress bar with glow effect
- Shimmer animation during upload
- Success checkmark with green glow
- Error state with retry button

### Responsive Design

[](#responsive-design)

All components are fully responsive and work on mobile devices.

Troubleshooting
---------------

[](#troubleshooting)

### Upload returns 500 error

[](#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_filesize` in php.ini

### Files not showing

[](#files-not-showing)

1. Clear cache: `php artisan cache:clear`
2. Check tenant scope is correct
3. Verify files exist in database

### Modal not opening

[](#modal-not-opening)

1. Check browser console for JS errors
2. Ensure Alpine.js is loaded
3. Clear Filament cache: `php artisan filament:cache-components`

License
-------

[](#license)

MIT License - see LICENSE file for details.

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance87

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity62

Established project with proven stability

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Recently: every ~21 days

Total

24

Last Release

62d ago

PHP version history (2 changes)1.0.0PHP ^8.2

1.0.1PHP ^8.1|^8.2|^8.3|^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/708233f4eef983f8ba8d7c7044ff49879634366c8561cc68faa0098082efe071?d=identicon)[georgemosesgroup](/maintainers/georgemosesgroup)

---

Tags

laravelfile managermedia librarymulti-tenancyfile-uploadfilamentdrag-dropadmin-panelmedia pickerfile-picker

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/georgemosesgroup-filament-media-library/health.svg)

```
[![Health](https://phpackages.com/badges/georgemosesgroup-filament-media-library/health.svg)](https://phpackages.com/packages/georgemosesgroup-filament-media-library)
```

###  Alternatives

[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)[mradder/filament-logger

Audit logging, activity tracking, exports, alerts, and dashboards for Filament admin panels.

2310.5k](/packages/mradder-filament-logger)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17758.9k2](/packages/stephenjude-filament-jetstream)[a2insights/filament-saas

Filament Saas for A2Insights

171.5k](/packages/a2insights-filament-saas)[guava/filament-knowledge-base

A filament plugin that adds a knowledge base and help to your filament panel(s).

210140.2k1](/packages/guava-filament-knowledge-base)[stephenjude/filament-debugger

About

104150.5k2](/packages/stephenjude-filament-debugger)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
