What's new in v0.1.0

v0.1.0 May 20, 2026

First tracked release. Early beta. Earlier history not recorded — see git log for changes prior to release-tracker adoption.

Filament Media — Documentation

Filament Media — Media Manager for Filament

Latest Version PHP Version Filament Tests Total Downloads License

A full-featured Media Manager plugin for Filament v4 and v5. Upload, organise, tag, version, and serve media files across local and cloud storage — with a modern UI, fine-grained access control, and a developer-friendly service architecture. The foundation that codenzia/filament-dam builds its enterprise DAM features on top of.

Try it live: A working integration is included in the Codenzia plugins demo at /admin/demo/media.

Features

File Management — Drag-and-drop uploads with progress tracking, chunked uploads for large files, upload from URL (with SSRF protection), multi-file selection, batch operations, copy/move/rename, alt text, automatic thumbnails with optional watermarks.

Folders — Nested folder structure with unlimited depth, color-coded folders, drag-and-drop organization, automatic folder resolution from file paths.

Tags & Collections — Tag files and folders, organize into named collections, filter and search by tags, bulk tagging, popular tags with usage counts.

Custom Metadata — Define custom fields (text, number, date, select, boolean, URL), attach to files, search and filter by metadata, auto-extract EXIF data.

Search — Database search out of the box, optional Laravel Scout integration, search by name, tags, metadata, file type, and date range.

Versioning — Upload new versions, view history with changelogs, revert to any previous version, configurable retention with auto-prune.

Export & Import — Export as ZIP with metadata manifest, import from ZIP or local folder with automatic metadata restoration.

Organization — Favorites, recent items, type filters (image, video, document, audio, archive), sort by name/date/size, grid and list views, breadcrumb navigation.

Trash & Recovery — Soft delete with trash folder, restore, permanent delete.

Preview — Full-screen gallery modal with version history, image/video/audio preview, document preview (PDF, Office via Google/Microsoft viewers), keyboard navigation.

UI — Responsive design, dark mode, configurable theme colors, context menu, details panel, drag-and-drop between folders, multi-select with Ctrl/Cmd and Shift.

Visibility & Access Control — Per-file public/private visibility, HMAC-SHA256 hash verification for private URLs, custom authorization callbacks, automatic file movement between storage disks, per-user media scoping.

Cloud Storage — Local, Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabi, Backblaze B2, BunnyCDN.

Developer Tools — 15 singleton services with DI, 16 Laravel events, MediaFileUpload and MediaPickerField form components, MediaFileGrid / MediaFileList / MediaFiles embeddable Livewire components, FilesUploadWidget, HasMediaFiles and InteractsWithMediaCollections traits, MediaAdder fluent builder, typed exceptions, query scopes, per-panel page visibility, configurable navigation.

Keyboard Shortcuts

Shortcut Action
Arrow Keys Navigate between items
Enter Open folder or preview file
Space Toggle selection
Ctrl/Cmd+A Select all
Delete Move to trash
F2 Rename
Escape Clear selection / Close preview
Arrow Left/Right Previous/next in preview

Requirements

  • PHP 8.2+
  • Laravel 11+
  • Filament 4.0+
  • GD or Imagick PHP extension (for thumbnails)
  • ZIP PHP extension (for export/import and multi-file download)

Installation

Publish and run migrations:

Publish the config:

Optionally publish views:

Setup

Register the Plugin

Control which pages are registered per panel:

Storage Link

For local storage:

Custom Theme (Tailwind v4)

If your panel uses a custom theme (->viteTheme()), add these @source directives to your theme CSS so Tailwind discovers the package's utility classes:

Then rebuild: npm run build

This is only needed with custom themes. Filament's default theme works without changes.

Configuration

The config file (config/media.php) provides full control over all options.

Feature Flags

Storage Driver

Navigation

Theme Colors

Colors are injected as CSS custom properties (--fm-*) with separate light and dark mode values:

Upload Limits

Thumbnails & Watermarks

Private Files

Search & Versioning

Usage

Media Manager Page

Available at /admin/media (or your panel prefix + /media).

Programmatic Access

All operations use dedicated service classes:

Upload methods return MediaFile directly and throw MediaUploadException on failure.

File Visibility & Access Control

Files have a visibility attribute — public (default) or private. Public files are served via direct storage URL. Private files are served through an authenticated controller with HMAC-SHA256 hash verification.

Changing Visibility

On local storage, files and thumbnails are physically moved between disks.

How Private URLs Work

Public files: /storage/photos/image.jpg Private files: /media/private/{hash}/{id}

The hash is an HMAC-SHA256 of the file ID, keyed to APP_KEY. URLs cannot be guessed or enumerated without the secret key. The controller verifies authentication and authorization before streaming. Append ?download=1 to force download.

Custom Authorization

The callback receives the MediaFile and the authenticated user (or null). Return true to allow, false to deny. Public files bypass the callback.

Per-User Media Scoping

Control which files each user sees in the Media page:

The callback applies a global scope on MediaFile and MediaFolder queries across all views (media, trash, recent, favorites, collections). Not invoked when no user is authenticated.

scopeMediaQueryUsing() controls query-level filtering (what appears in the UI), while authorizeFileAccessUsing() controls file-level download authorization. Use both together for complete access control.

Artisan Commands

Form Components

MediaFileUpload

Pre-configured FileUpload that reads settings from config/media.php:

Automatically resolves MIME types, respects max file size and server limits, uses the configured storage disk, and preserves original filenames.

MediaPickerField

File picker for selecting existing media:

Direct Upload

By default, the field shows a single "Browse Media" button that opens the full media library picker. Enable directUpload() to add a quick "Upload File" option alongside it — the button becomes a dropdown with both choices:

The upload zone supports drag-and-drop and uses the same upload endpoint as the media library. Uploaded files are saved to the root folder and the field state is updated automatically.

To enable direct upload globally for all MediaPickerField instances, set the config default:

You can still override the global default per-field:

Per-Field File Type Control

By default, uploads are validated against the global allowed_mime_types in config/media.php. Two methods let you customize this per field:

Both methods enforce validation on both client-side (browser) and server-side (upload endpoint). Server-side overrides are protected with HMAC-SHA256 signatures to prevent tampering.

Display Styles

The field supports five visual styles via displayStyle():

Style Best for Drag & Drop Description
compact Documents, mixed files No Text links + chip list with small icons
dropdown Documents, mixed files No Dropdown button + chip list with small icons
thumbnail Images, visual content Yes Large preview card, hover overlay with change/remove actions
integratedLinks Images + text links Yes Thumbnail preview area with text links below
integratedDropdown Images + dropdown button Yes Thumbnail preview area with dropdown button below

To set a global default for all fields:

Per-field values always override the config default.

Preview Size

Control the dimensions of the thumbnail preview container (used by thumbnail, integratedLinks, and integratedDropdown styles). The image itself always maintains its natural aspect ratio via object-contain.

Default: 12rem width with aspect-square (192x192px). Any CSS length value works (rem, px, %, etc.). Global defaults can be set in config:

Chip Size

Control the size of the file chips used in compact and dropdown display styles. This affects the thumbnail size, icon size, and text size within each chip.

Available sizes:

Size Thumbnail Text Description
xs 20px 12px Tiny — minimal footprint
sm 32px 14px Small — default
md 48px 14px Medium — easier to see previews
lg 64px 16px Large — prominent file display
xl 80px 18px Extra large — visual emphasis
2xl 96px 20px Huge — maximum preview size

Global default can be set in config:

Lightbox Size

Control the maximum dimensions of the full-screen image preview (lightbox) that appears when clicking a thumbnail. By default, the image fills the available viewport.

Global defaults can be set in config:

Lightbox Opacity

Control the backdrop opacity of the lightbox overlay. The value is a percentage from 0 (fully transparent) to 100 (fully opaque). Default: 80.

Global default can be set in config:

Method Description
multiple() Allow selecting multiple files
imageOnly() Restrict to images
videoOnly() Restrict to videos
documentOnly() Restrict to documents
acceptedFileTypes(array) Custom MIME types for picker filtering
includeFileTypes(array) Add extra file extensions to the global allowed list for this field
allowedFileTypesOnly(array) Restrict uploads to ONLY these file extensions (ignores global config)
maxFiles(int) Limit selections
directory(string) Default upload directory
collection(string) Auto-assign collection
directUpload(bool) Show inline upload option alongside media browser (default: false, or from config)
displayStyle(string) Visual style: 'compact', 'dropdown', 'thumbnail', 'integratedLinks', or 'integratedDropdown' (default: 'compact', or from config)
previewWidth(string) Preview container width as CSS value, e.g. '16rem', '256px' (default: '12rem', or from config)
previewHeight(string) Preview container height as CSS value, e.g. '8rem', '128px'. Setting height removes aspect-square (default: null / aspect-square, or from config)
chipSize(string) Chip size preset: 'xs', 'sm', 'md', 'lg', 'xl', '2xl'. Controls thumbnail, icon, and text size in compact/dropdown styles (default: 'sm', or from config)
lightboxMaxWidth(string) Lightbox image max width as CSS value, e.g. '800px', '50vw' (default: null / full viewport, or from config)
lightboxMaxHeight(string) Lightbox image max height as CSS value, e.g. '600px', '80vh' (default: null / full viewport, or from config)
lightboxOpacity(int) Lightbox backdrop opacity as percentage 0–100 (default: 80, or from config)

Livewire Components

MediaFileGrid

Displays a grid of media files with full context menu. The parent model must use HasMediaFiles:

MediaFileList

Same features as MediaFileGrid in a table/list layout:

MediaFiles

Unified viewer with a toggle between grid and list layouts:

Shared Props

All three components accept the same props:

Prop Type Default Description
record Model|null null Parent model (single-model mode)
relationship string 'files' Relationship method name
fileableType string|null null Morph class (multi-model mode)
fileableIds array [] Model IDs (multi-model mode)
deletable bool false Enable trash/delete
columns string responsive grid Tailwind grid classes
emptyMessage string 'No files attached' Empty state message
contextMenu bool true Enable right-click menu
contextMenuExclude array [] Menu items to hide

Context menu keys: preview, download, copy_link, view_parent, rename, alt_text, tags, collections, versions, metadata, export, visibility, favorites, trash.

FilesUploadWidget

Filament widget for adding uploads to any resource page:

Attaching Media to Models

Setup

Uploading

Attaching & Detaching

Querying

URL Attributes on MediaFile

Physical File Deletion

Named Media Collections

For models that need structured, constrained media:

Method Description
singleFile() One file only — new uploads auto-detach the previous
onlyKeepLatest(int) Keep at most N files, auto-prune oldest
acceptsMimeTypes(array) Restrict MIME types (supports image/* wildcards)
useFallbackUrl(string) URL returned when collection is empty

Collections build on the tag system (MediaTag with type='collection'). No additional migrations needed.

Error Handling

Method When Thrown
invalidFileType() MIME type not in allowed list
fileTooLarge(string $size) Exceeds configured max size
unableToWrite(string $folder) Storage write failed
networkError(string $url) URL download failed
ssrfBlocked(string $message) URL targets internal network
invalidUrl() Malformed or empty URL
invalidPath() Local file path doesn't exist
noFileDetected() Could not detect file type
tempFileError() Temp file creation failed

Automatic Folder Resolution

When creating a MediaFile without an explicit folder_id, the folder is resolved from the url path:

Auto-resolution only runs when folder_id is 0 or not set. Uses firstOrCreate() internally, so concurrent uploads are safe.

Tags & Collections

Custom Metadata

Search

File Versioning

Export & Import

Exports with metadata include a manifest.json preserving tags, collections, and custom metadata.

Orphan File Management

Manage files in storage that have no database record:

Also available via the Storage Scanner section in Media Settings.

Events

All operations dispatch Laravel events:

File Events

Event Properties
MediaFileUploaded MediaFile $file
MediaFileRenaming MediaFile $file, string $newName, bool $renameOnDisk
MediaFileRenamed MediaFile $file
MediaFileDeleting MediaFile $file
MediaFileDeleted MediaFile $file
MediaFileTrashed MediaFile $file
MediaFileRestored MediaFile $file
MediaFileMoved MediaFile $file, $oldFolderId, $newFolderId
MediaFileCopied MediaFile $newFile, MediaFile $originalFile
MediaFileTagged MediaFile $file, array $tagIds
MediaFileVersionCreated MediaFile $file, MediaFileVersion $version

Folder Events

Event Properties
MediaFolderCreated MediaFolder $folder
MediaFolderRenaming MediaFolder $folder, string $newName, bool $renameOnDisk
MediaFolderRenamed MediaFolder $folder
MediaFolderDeleted MediaFolder $folder
MediaFolderMoved MediaFolder $folder, $oldParentId, $newParentId

Permissions

Permission Description
folders.create Create new folders
folders.edit Edit/rename folders
folders.trash Move folders to trash
folders.destroy Permanently delete folders
folders.favorite Add folders to favorites
files.create Upload files
files.read View files
files.edit Edit files (rename, alt text)
files.trash Move files to trash
files.destroy Permanently delete files
files.favorite Add files to favorites
settings.access Access settings page

Security

  • Private File Access — Authenticated controller with customizable authorization callbacks
  • HMAC-SHA256 URLs — Private file URLs keyed to the application secret, not guessable
  • SSRF Protection — URL downloads validated against internal networks, cloud metadata IPs, and configurable domain allowlists
  • XSS Prevention — User content escaped via SafeContentService
  • File Validation — Uploads validated for MIME type and size
  • Rate Limiting — Private file routes throttled
  • CSRF Protection — All Livewire actions protected

Architecture

Services (registered as singletons)

Service Responsibility
UploadService File uploads, validation, SSRF checks
FileOperationService Rename, copy, move, delete, visibility changes
ImageService Thumbnails, watermarks, image processing
MediaUrlService URL generation, path resolution, MIME detection
StorageDriverService Cloud disk configuration (S3, R2, DO, etc.)
FavoriteService Favorites and recent items
TagService Tags and collections
MetadataService Custom metadata fields
SearchService Full-text search (DB or Scout)
VersionService File versioning
ExportImportService ZIP export/import with metadata
OrphanScanService Storage scan, orphan import/delete
ThumbnailService Image resize and crop

Support Classes

Class Purpose
MediaAdder Fluent builder for uploads (->usingName()->toCollection()->save())
MediaCollection Collection definition with constraints
MediaHash HMAC-SHA256 hash generation for URL obfuscation
MediaUploadException Typed exceptions for upload failures

Traits

Trait Purpose
HasMediaFiles Polymorphic relationships, attach/detach/sync, fluent upload builder
InteractsWithMediaCollections Named collections with constraints

Livewire Components

Component Purpose
Media Main media manager page
UploadModal File uploads with progress tracking
PreviewModal Gallery-style preview with version history
MediaPicker Embeddable file browser for MediaPickerField
MediaFileGrid File grid with context menu
MediaFileList File list/table with context menu
MediaFiles Unified viewer with grid/list toggle

Extending

Override any service:

Listen to events:

Testing

Image Gallery Component

A standalone Alpine.js image gallery with lightbox, thumbnails, keyboard navigation, and RTL support. Works with any array of image URLs — no dependency on the media manager models.

Prop Type Default Description
urls array [] Array of image URLs
alt string '' Alt text for accessibility and lightbox title

Features: main image display, prev/next arrows, thumbnail strip, fullscreen lightbox overlay, keyboard navigation (arrow keys + Escape), image counter badge, RTL-aware arrow direction, no-images placeholder.

Changelog

Please see CHANGELOG for recent changes.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

This project uses a dual license:

  • Open Source — Available under the MIT License for OSI-approved open source projects.
  • Commercial — A commercial license is required for proprietary projects. Visit codenzia.com for options.

See LICENSE.md for full details.

Powered by Codenzia
✓ Thanks! We read every message.