Appearance
Models & Blade
Use the HasMediaLibrary trait to attach library files to any Eloquent model, and the Blade components to show them on your site.
The HasMediaLibrary trait
php
use Hoceineel\FilamentMediaLibrary\Concerns\HasMediaLibrary;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasMediaLibrary;
}Files are grouped in named collections. A collection is just a string, such as gallery or downloads. The default collection is default.
| Method | Returns |
|---|---|
mediaLibraryItems(?string $collection = null) | A MorphToMany relation, ordered. With no collection, every attached file. |
getMediaLibraryItems(string $collection = 'default') | A collection of MediaItem. |
getFirstMediaLibraryItem(string $collection = 'default') | The first MediaItem, or null. |
getFirstMediaLibraryUrl(string $collection = 'default', string $conversion = '') | The first file's URL, or null. |
syncMediaLibraryItems($items, string $collection = 'default') | Replaces the collection with the given ids or items, in that order. |
attachMediaLibraryItem($item, string $collection = 'default') | Adds one file at the end of the collection. |
mediaAttachments() | The raw MorphMany of attachment rows. |
php
$post->syncMediaLibraryItems([4, 8, 15], 'gallery');
$post->attachMediaLibraryItem($item, 'gallery');
$post->getMediaLibraryItems('gallery');
$post->getFirstMediaLibraryItem('cover');
$post->getFirstMediaLibraryUrl('gallery', 'thumb');
$post->mediaLibraryItems('gallery')->get();Sync only accepts ids that exist for the current tenant. Anything else is dropped without an error. Attachments are deleted with the model, except when the model uses soft deletes and is only soft deleted.
The picker field in relationship mode calls syncMediaLibraryItems() for you, using the field name as the collection unless you set another.
Avoid N+1 queries
getMediaLibraryItems() uses the loaded relation when it is available, so eager load it for lists:
php
$posts = Post::query()->with('mediaLibraryItems.media')->get();
foreach ($posts as $post) {
$post->getMediaLibraryItems('gallery');
}Storing ids in a column
You do not need the trait to store a selection. A picker in column mode saves ids in an attribute, and you read it with the Blade components below or with the model:
php
use Hoceineel\FilamentMediaLibrary\Models\MediaItem;
$cover = MediaItem::query()->find($post->cover_id);Reading a file
Every MediaItem has these methods:
| Method | Returns |
|---|---|
url(string $conversion = '') | URL of the original, or of a conversion. |
thumbnailUrl() | The thumb conversion, or the original for images without one. |
previewUrl() | The preview conversion, or the original for images without one. |
conversionUrlOrOriginal(string $conversion) | The conversion if it exists. For images, the original if not. For other files, null. |
srcset(string $conversion = 'preview') | A srcset string of responsive sizes, or an empty string. |
focalPosition() | A CSS object-position value such as 32% 18%. Defaults to 50% 50%. |
php
$item->url();
$item->url('hero');
$item->conversionUrlOrOriginal('hero');
$item->srcset('preview');
$item->focalPosition();Public files on a public disk get direct URLs. Files on a private disk, and files marked Only me, get short-lived signed or temporary URLs (temporary_url_minutes, 30 by default). srcset() returns an empty string for those files, and for conversions without responsive images. See Storage.
Other useful properties on the item are name, alt, caption, description, width, height, mime_type, extension and size.
Conversions
Conversions are presets in config/filament-media-library.php. Two ship by default:
php
'conversions' => [
'thumb' => ['width' => 480, 'height' => 480, 'fit' => 'crop', 'format' => 'webp', 'queued' => false],
'preview' => ['width' => 1600, 'height' => 1600, 'fit' => 'contain', 'format' => 'webp', 'queued' => true, 'responsive' => true, 'optimize' => true],
],Each preset accepts these keys:
| Key | Default | Meaning |
|---|---|---|
width, height | none | Target size in pixels. A missing side defaults to 4096. |
fit | contain | crop fills exactly width by height and needs both. Anything else fits inside the box without cropping. |
format | webp | Output format. |
queued | false | Generate on the queue instead of during the upload. |
responsive | false | Also build the smaller sizes used by srcset. |
optimize | false | Run Spatie's image optimizers. Slow, best queued. |
Add your own preset by adding a key:
php
'hero' => ['width' => 2400, 'height' => 1000, 'fit' => 'crop', 'queued' => true],New uploads get the conversion. Build it for existing files with:
bash
php artisan media-library:regenerate --only=hero --missingCropped conversions centre on the focal point set in the inspector. When a focal point changes, the file's conversions are rebuilt on the queue, so keep a worker running. See Commands.
Conversions are built for images. A non-image file normally has none, and then thumbnailUrl() and conversionUrlOrOriginal() return null.
Blade components
Both components are registered by the package. Outside Filament panels, enable standalone mode and load Filament's assets first: see Outside Panels.
x-media-library-image
blade
<x-media-library-image
:item="$post->cover_id"
conversion="preview"
sizes="(min-width: 1024px) 50vw, 100vw"
class="aspect-video w-full rounded-xl object-cover"
/>| Attribute | Default | Meaning |
|---|---|---|
item | none | A MediaItem, an id, or null. With null or a missing file, nothing is rendered. |
conversion | preview | Which conversion to use. Uses the original if it does not exist. |
sizes | 100vw | The sizes attribute. Only output when there is a srcset. |
lazy | true | Adds loading="lazy" and decoding="async". Pass :lazy="false" for images above the fold. |
Any other attribute, such as class or id, is passed to the <img>. The component also sets:
altfrom the file's alt text, or an empty string.widthandheightfrom the original file. Addobject-coverand a fixed ratio class when you use a cropped conversion.srcsetfrom the responsive sizes, when the conversion has them.style="object-position: ..."from the focal point, so a cropped image keeps the subject in frame.
Passing an item you already loaded avoids a query: :item="$post->getFirstMediaLibraryItem('cover')".
x-media-library-gallery
blade
<x-media-library-gallery :record="$post" collection="gallery" :columns="3" aspect-ratio="4:3" />
<x-media-library-gallery :items="$post->gallery_ids" :lightbox="false" :captions="false" />| Attribute | Default | Meaning |
|---|---|---|
record | none | A model with HasMediaLibrary. Use with collection, or with attribute for a column. |
collection | none | Attachment collection to show. |
attribute | none | Column on record holding the ids. Use it instead of collection. |
items | none | A list of ids, a single id, or an Eloquent collection of items. |
conversion | thumb | Conversion used for the tiles. |
columns | 4 | Grid columns. |
aspect-ratio | 1:1 | Ratio of each tile. |
captions | true | Show the caption, or the name, under each tile. |
lightbox | true | Open files full screen on click. |
Give it either items, or record with collection or attribute. A record with neither shows nothing. The items form only shows files the current user can see, so other people's private files are left out.
The gallery uses Alpine for the lightbox. Pages built with @filamentScripts already have it. It is the same grid as the infolist entry.