Skip to content

Media ​

The core adds a Media library at /admin/media, for every role. A file is uploaded once, several at a time if needed, and can then be used by any record of the site. Each file has a name and, for an image, an alternative text per site language.

Every file is a record of the library. A field that takes a file saves the id of a record, never a path.

Image sizes ​

Every image gets these sizes at upload, as WebP files next to the original:

SizeResult
thumb400 × 400, cropped to fill the square
medium800 wide, same proportions
large1600 wide, same proportions

An image is never enlarged, and the original is kept as uploaded. Animated GIFs, PDFs and other documents keep the original only.

An upload never fails because of a size. An image too large to resize within PHP's memory_limit with GD (about 15 bytes per pixel: a 24-megapixel photo needs about 360 MB) keeps the original only. The error is written to the log.

The sizes are made in the upload request, not on a queue, because shared hosting often has no queue worker.

Giving a model an image ​

Add a nullable foreign key to the mela_media table for one image, or a JSON list of ids for a gallery:

php
// Migration
$table->foreignId('cover_id')->nullable()->constrained('mela_media')->nullOnDelete();
$table->json('gallery')->nullable();
php
use Melasistema\MelaCms\Models\Media;

class Article extends Model
{
    protected function casts(): array
    {
        return ['gallery' => 'array'];
    }

    public function cover(): BelongsTo
    {
        return $this->belongsTo(Media::class, 'cover_id');
    }

    public function galleryMedia(): Collection
    {
        return Media::inOrder($this->gallery);   // skips a file that was deleted
    }
}

In the Filament form, MediaPicker picks a file from the library, or uploads a new one into it:

php
use Melasistema\MelaCms\Filament\Forms\MediaPicker;

MediaPicker::make('cover_id')->images(),             // saves the id of the file
MediaPicker::make('gallery')->images()->multiple(),  // saves a list of ids

images() limits the field to images. MediaPicker extends Filament's Select, so required(), label() and the rest work as usual.

In a view ​

blade
@if ($article->cover)
    <img
        src="{{ $article->cover->url('large') }}"
        srcset="{{ $article->cover->srcset() }}"
        sizes="(min-width: 1024px) 800px, 100vw"
        width="{{ $article->cover->width }}"
        height="{{ $article->cover->height }}"
        alt="{{ $article->cover->alt }}"
    >
@endif
MethodReturns
url()The address of the original file
url('thumb')The address of a size. A file without that size gives the original
srcset()The sizes that keep the proportions, for the srcset attribute. null when there are none
altThe alternative text in the language of the request, with the default language as fallback
width, heightThe size of the original image
isImage()Whether the file is an image

Eager-load the relation in lists, for example Article::with('cover').

Configuration ​

php
// config/mela-cms.php
'media' => [
    'disk' => 'public',
    'directory' => 'media',
    'max_size' => 10240,   // kilobytes
    'accepted_types' => ['image/jpeg', 'image/png', 'image/webp', 'image/gif', 'application/pdf'],
    'conversions' => [
        'thumb' => ['width' => 400, 'height' => 400],
        'medium' => ['width' => 800],
        'large' => ['width' => 1600],
    ],
    'quality' => 80,
],

A size with a width and a height is cropped to fill them. A size with only one of the two keeps its proportions. After changing conversions or quality, make the sizes of the files already uploaded again:

bash
php artisan mela:media-regenerate

The disk must be public. With the default disk the files are served through the public/storage link, which mela:install, mela:update and the deploy create. PHP's upload_max_filesize and post_max_size must allow max_size, and Livewire has its own limit of 12 MB per upload.

SVG

SVG is not accepted by default. An SVG file can carry a script, and it would run on your domain. Add image/svg+xml to accepted_types only if everyone who can log in is trusted.

Changing the screen ​

Extend Melasistema\MelaCms\Filament\Resources\Media\MediaResource, override formComponents() or tableColumns(), and set your class as resources.media in the config. To change who may use the library, register your own policy for Media with Gate::policy().

Known limits ​

  • The library does not show where a file is used before you delete it.
  • A gallery cannot be reordered by dragging.
  • The file of a record cannot be replaced.
  • There are no folders or tags.

Code released under the MIT License. The MelaCMS name and logo are trademarks, see Brand.