PHPackages                             aboleon/metaframework-mediaclass - 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. [File &amp; Storage](/categories/file-storage)
4. /
5. aboleon/metaframework-mediaclass

ActiveLibrary[File &amp; Storage](/categories/file-storage)

aboleon/metaframework-mediaclass
================================

Mediaclass media management components for MetaFramework

1.1.13(1w ago)01061MITPHPPHP ^8.3

Since Jan 12Pushed 1mo agoCompare

[ Source](https://github.com/aboleon/metaframework-mediaclass)[ Packagist](https://packagist.org/packages/aboleon/metaframework-mediaclass)[ RSS](/packages/aboleon-metaframework-mediaclass/feed)WikiDiscussions 1.x Synced 1w ago

READMEChangelogDependencies (90)Versions (60)Used By (1)

MetaFramework Mediaclass
========================

[](#metaframework-mediaclass)

[![Tests](https://github.com/aboleon/metaframework-mediaclass/actions/workflows/tests.yml/badge.svg)](https://github.com/aboleon/metaframework-mediaclass/actions)[![codecov](https://camo.githubusercontent.com/dcba6aa2185c83431cbdcb2879b328cc9514733bf46ee1cc73d59c13dbffe61c/68747470733a2f2f636f6465636f762e696f2f67682f61626f6c656f6e2f6d6574616672616d65776f726b2d6d65646961636c6173732f67726170682f62616467652e737667)](https://codecov.io/gh/aboleon/metaframework-mediaclass)[![Latest Version on Packagist](https://camo.githubusercontent.com/efce5c25947bfb1a8e3cf85c347e4868938d679b8e7ab3a99183e55648bd8356/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f61626f6c656f6e2f6d6574616672616d65776f726b2d6d65646961636c6173732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-mediaclass)[![Total Downloads](https://camo.githubusercontent.com/ef2448aa3b3403a498ffb65880469722976dae10418f3f721b97ef758301fa9c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f61626f6c656f6e2f6d6574616672616d65776f726b2d6d65646961636c6173732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-mediaclass)[![PHP Version](https://camo.githubusercontent.com/bceafd85b548dcfb5bb1b9834d9c333ffdbfb36fba65cf400ddf7e800f0152b6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f61626f6c656f6e2f6d6574616672616d65776f726b2d6d65646961636c6173732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-mediaclass)[![License](https://camo.githubusercontent.com/d0e99fe8c995a8ce67db1d82931e9f3ca1e71aee70a9c03c9fe0cfe26ae3c5ca/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f61626f6c656f6e2f6d6574616672616d65776f726b2d6d65646961636c6173732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-mediaclass)

Media management components for Laravel applications. This package provides upload UI, database persistence, image resizing, optional cropping, and helpers to retrieve and render media for Eloquent models.

Installation
------------

[](#installation)

```
composer require aboleon/metaframework-mediaclass
```

Publish package resources after install or update:

```
php artisan mediaclass:update --force
```

The update command replaces the package-owned `public/vendor/mfw-mediaclass` directory before publishing. This removes assets deleted by newer package versions instead of leaving stale files from older releases. Do not customize files inside that published asset directory.

On first install, publish the config without `--force`, then set its `disk` to the application filesystem disk that owns the media paths:

```
php artisan mediaclass:update --config
```

Normal package updates never publish the config, including when `--force` is used. This preserves application-owned disk, dimensions, subgroup, and path settings. Use `--config --force` only when intentionally replacing the application config with package defaults.

When a release adds migrations, publish and run them explicitly:

```
php artisan mediaclass:update --force --migrate
```

Use `--views` only when the application needs to customize the package Blade views. Views are not published by default so package updates can keep improving the upstream UI.

Use `--lang` only to create application-owned translation overrides. Package translations load directly from the dependency and are not published during a normal update.

The stored-media component loads LightGallery `2.8.3` from `https://cdnjs.cloudflare.com`, including its bundled CSS and the core, zoom, thumbnail, and video scripts. The package does not publish a local LightGallery distribution. Applications with a Content Security Policy must allow this host in `script-src` and `style-src`.

Version Tracks
--------------

[](#version-tracks)

Mediaclass `0.x` is the jQuery uploader line. Applications that want the existing jQuery UI and do not want the v1 Svelte UI should require the `0.x`track explicitly:

```
composer require aboleon/metaframework-mediaclass:"0.*"
```

For the current stable jQuery release line only:

```
composer require aboleon/metaframework-mediaclass:"^0.16"
```

Mediaclass `1.x` is the Svelte UI line. The Svelte assets are built and shipped inside the Composer package, so consuming Laravel applications do not need Node, npm, or a Svelte build step.

The `1.x` package does not ship or load Blueimp jQuery File Upload. Its uploader, video URL form, queue, progress state, and validation UI are Svelte. jQuery is still required by the current media-management bridge for stored-media sorting, deletion, descriptions, cropping, subgroups, and LightGallery integration.

During v1 development, applications can test the branch with Composer's dev constraint:

```
composer require aboleon/metaframework-mediaclass:"1.x-dev"
```

### Frontend Asset Development

[](#frontend-asset-development)

The v1 frontend source lives in `resources/svelte`. `Uploadable.svelte` owns the upload UI and `media-manager.js` owns stored-media interactions. Vite compiles both into the single shipped `public/vendor/mfw-mediaclass/mediaclass-uploader.js` bundle. Package maintainers must run the frontend checks and rebuild the shipped bundle before tagging a release:

```
npm install
npm run check
npm run build
```

Uploader styles live in `public/vendor/mfw-mediaclass/css/styles.css` and are processed by the existing CSSCrush integration. Svelte components must not contain component-level style blocks or inject CSS into the compiled JavaScript bundle.

The Vite build disables `publicDir` intentionally because the bundle output is inside the package `public` tree. Do not re-enable public copying for this build.

### Blade Components

[](#blade-components)

The active v1 Blade surface is:

- `` for the Svelte mount point and media context.
- `` for server-rendered existing media.
- `` and `` for frontend rendering.
- Internal crop and confirmation modal components used by `uploadable`.

The old Blueimp upload-template component was removed in `1.x`; it is not a supported Blade API.

The small published `jcrop` directory remains because the active crop editor still loads Jcrop. It is independent from the removed Blueimp uploader.

Laravel Compatibility
---------------------

[](#laravel-compatibility)

The package supports Laravel majors through explicit Illuminate constraints in `composer.json`, currently `^11.0|^12.0|^13.0`. A future Laravel major does not automatically require a Mediaclass major release. The package should widen its Laravel constraints and tag a minor or patch release when the public API and published assets remain compatible.

Use a new Mediaclass major only when the package drops an older Laravel major, changes the public PHP or Blade contract, changes installation behavior in a breaking way, or replaces an implementation detail that applications can reasonably depend on.

The current v1 direction keeps Mediaclass Laravel-bound with a shipped Svelte bundle. If Mediaclass later needs to live as a framework-neutral uploader, the better split is a Lit + TypeScript web-component package with a Laravel bridge package around routes, persistence, configuration, and Blade helpers. That split is larger than the v1 Svelte migration and should be treated as a separate product boundary.

Model Setup
-----------

[](#model-setup)

```
use Illuminate\Database\Eloquent\Model;
use MetaFramework\Mediaclass\Contracts\MediaclassInterface;
use MetaFramework\Mediaclass\Concerns\Mediaclass as MediaclassTrait;

class Post extends Model implements MediaclassInterface
{
    use MediaclassTrait;

    public function mediaclassSettings(): array
    {
        return [
            'cover' => [
                'label' => 'Cover',
                'width' => 1600,
                'height' => 900,
                'cropable' => true,
            ],
            'gallery' => [
                'label' => 'Gallery',
                'width' => 1200,
                'height' => 800,
            ],
        ];
    }
}
```

---

Two Groups Example (Cover + Gallery)
------------------------------------

[](#two-groups-example-cover--gallery)

Use group keys in `mediaclassSettings()` to define the required dimensions per group:

```
public function mediaclassSettings(): array
{
    return [
        'cover' => [
            'label' => 'Cover',
            'width' => 1600,
            'height' => 900,
            'cropable' => true, // single crop using the group dimensions
        ],
        'gallery' => [
            'label' => 'Gallery',
            'width' => 1200,
            'height' => 800,
            // 'cropable' => ['thumb' => [400, 300]] // optional extra crops
        ],
    ];
}
```

If no group is defined, the package falls back to the default sizes defined in `config/mfw-mediaclass.php` under `dimensions`.

---

Group-Specific Sizes
--------------------

[](#group-specific-sizes)

You can define multiple sizes for a single group using a `sizes` array. These sizes will be used for resizing and for size keys when calling `url('key')`:

```
public function mediaclassSettings(): array
{
    return [
        'cover' => [
            'label' => 'Cover',
            'sizes' => [
                'xl' => ['width' => 1600, 'height' => 900],
                'sm' => ['width' => 1200, 'height' => 500],
            ],
            'cropable' => true, // uses the largest size as the crop target
        ],
    ];
}
```

If `sizes` is not provided for a group, the package uses the single `width` / `height` pair for that group, or falls back to the global `dimensions` defaults.

**Note:** Upload processing relies on Intervention Image. If Intervention Image is not installed, upload tests that hit the upload controller will be skipped.

---

Displaying Images
-----------------

[](#displaying-images)

### Fluent API (Recommended)

[](#fluent-api-recommended)

The simplest way to display images from your models:

```
// Get URL
$url = $post->img('cover')->url();
$url = $post->img('cover')->url('lg');    // specific size

// Get img tag
$html = $post->img('cover')->img();
$html = $post->img('cover')
    ->class('rounded-lg shadow')
    ->alt('Product photo')
    ->lazy()
    ->img();

// Get cropped version
$url = $post->img('cover')->crop('banner')->url();

// Check if media exists
if ($post->img('cover')->exists()) {
    // ...
}

// Multiple images
foreach ($post->imgs('gallery') as $img) {
    echo $img->url();
}
```

### Available Methods

[](#available-methods)

MethodDescription`->url(?string $size)`Get URL (default: 'sm')`->img(?string $size)`Get `` tag`->picture(?array $breakpoints)`Get `` element`->background()`Get CSS background-image style`->urls()`Get all available URLs as array**Size Methods:**

```
->size('lg')      // Set size
->sm() / ->md() / ->lg() / ->xl()  // Shorthand
```

**Crop Methods:**

```
->crop('banner')  // Use specific crop
->hasCrop('banner')  // Check if crop exists
```

**HTML Attributes:**

```
->class('rounded')   // CSS classes
->addClass('shadow') // Add to existing classes
->alt('Description') // Alt text
->id('hero-image')   // ID attribute
->lazy()             // loading="lazy"
->eager()            // loading="eager"
->width(800)         // Width attribute
->height(600)        // Height attribute
->attr('data-id', 1) // Any attribute
->attrs(['class' => 'rounded', 'id' => 'img'])
->data('gallery', 'main')  // data-* attributes
```

**Fallback:**

```
->default('/img/fallback.png')  // Custom fallback URL
->noDefault()                    // No fallback image
```

### Blade Component

[](#blade-component)

```
{{-- Basic usage --}}

{{-- With attributes --}}

{{-- From model directly --}}

{{-- As URL only --}}

{{-- As picture element --}}

{{-- With specific crop --}}

```

**Component Attributes:**

AttributeTypeDescription`src`MediaBuilderFrom `$model->img('group')``model`objectModel instance (with `group`)`group`stringMedia group name`subgroup`stringMedia subgroup filter`size`stringImage size (sm, md, lg, xl)`type`stringOutput: img, url, picture, background`class`stringCSS classes`alt`stringAlt text`id`stringHTML id`lazy`boolEnable lazy loading`crop`stringSpecific crop key`default`stringFallback URL`noDefault`boolDisable fallback`data`arrayData attributes`breakpoints`arrayFor picture element### Direct Media Model Usage

[](#direct-media-model-usage)

```
// If you have a Media model directly
$media = Media::find(1);

$url = $media->url('lg');
$url = $media->crop('banner');
$html = $media->img('md', ['class' => 'rounded']);

// Fluent builder
$html = $media->builder()
    ->class('rounded')
    ->lazy()
    ->img();
```

---

Uploading Media
---------------

[](#uploading-media)

### Upload Component

[](#upload-component)

```

```

With options:

```

```

Applications can place group-specific controls in the component slot. The package then displays one **Save media settings** button for descriptions, stored video details, and the supplied settings:

```

        Display in the text flow

```

The button emits `mediaclass:save-settings` with the uploadable jQuery element. Applications can listen for that event and persist their own slot values:

```
$(document).on('mediaclass:save-settings', function (event, uploadable) {
    // Persist application-specific settings contained by uploadable.
});
```

### Stored Media Display (Admin)

[](#stored-media-display-admin)

```

```

### Dynamic Subgroups in the Upload UI

[](#dynamic-subgroups-in-the-upload-ui)

Mediaclass stores an optional `subgroup` on each media row. You can enable an admin-side subgroup selector for an uploadable group so editors can assign each uploaded image to a preset subgroup without creating separate upload slots.

Configure presets globally:

```
// config/mfw-mediaclass.php
'subgroups' => [
    'count' => 5,
    'label' => 'Group',
    'empty_label' => 'Normal flow',
    'key_prefix' => 'group_',
    'groups' => [
        'gallery' => true,
    ],
],
```

Or define explicit labels:

```
'subgroups' => [
    'groups' => [
        'gallery' => [
            'options' => [
                'featured' => 'Featured',
                'flow' => 'Flow',
            ],
        ],
    ],
],
```

You can also define subgroup presets on a model group:

```
public function mediaclassSettings(): array
{
    return [
        'gallery' => [
            'label' => 'Gallery',
            'width' => 1200,
            'height' => 800,
            'subgroups' => [
                'count' => 5,
                'label' => 'Group',
            ],
        ],
    ];
}
```

When subgroups are enabled, `` injects a select into each native uploaded image row. The select saves through the package AJAX route:

```
POST /mediaclass-ajax
action=saveSubgroup

```

The response triggers a jQuery document event:

```
$(document).on('mediaclass:subgroup-saved', function (event, result, uploadable, select) {
    // result.group, result.media_id, result.subgroup, result.uses_subgroups
});
```

Frontend rendering remains application-owned. A common pattern is to render media with `subgroup = null` in normal flow, and render media sharing the same subgroup as a grid.

### Processing After Save

[](#processing-after-save)

```
$post = Post::create($payload);
$post->processMedia();
```

---

Configuration
-------------

[](#configuration)

Publish application-owned configuration with `php artisan mediaclass:update --config`. The resulting `config/mfw-mediaclass.php` starts with:

```
return [
    'disk' => 'public',
    'dimensions' => [
        'xl' => ['width' => 1920, 'height' => 1080],
        'lg' => ['width' => 1400, 'height' => 788],
        'md' => ['width' => 700,  'height' => 394],
        'sm' => ['width' => 400,  'height' => 225],
    ],
];
```

### Localization

[](#localization)

Translations load from the package under the `mfw-mediaclass` namespace. Package code and application integrations can resolve a line with:

```
__('mfw-mediaclass::messages.buttons.save_media_settings');
```

Laravel automatically merges application overrides from its conventional vendor language directory. Override only the lines the application needs:

```
lang/vendor/mfw-mediaclass/fr/messages.php

```

```
