← All plugins

MoonShine Media Fields

Audio, AudioList, Video and VideoList fields with preview, playback modals and custom audio player.

Rating
Downloads
3
Version
1.1.0
Last updated
13.02.2026
MoonShine version
v4
Github stars
4
Yurii Bulavkin
Author
Yurii Bulavkin

MoonShine Media Fields

Audio, AudioList, Video and VideoList fields for MoonShine 4.x with preview, playback modals and custom audio player.

MoonShine Media Fields


Table of Contents


Requirements

  • PHP 8.2+
  • Laravel 11+
  • MoonShine 4.x
  • Alpine.js (included with MoonShine)

Installation

composer require goodappr/moonshine-media-fields
composer require goodappr/moonshine-media-fields

The package auto-registers MediaFieldsServiceProvider.


Configuration

Publish config (optional)

php artisan vendor:publish --tag=moonshine-media-fields-config
php artisan vendor:publish --tag=moonshine-media-fields-config

Creates config/media_fields.php:

<?php
 
return [
'audio' => [
'extensions' => ['mp3', 'wav', 'ogg', 'm4a', 'aac', 'flac', 'webm'],
'max_size_kb' => 20480,
'dir' => 'audio',
'default_preload' => 'metadata',
],
 
'video' => [
'extensions' => ['mp4', 'mov', 'avi', 'mkv', 'webm', 'flv', 'wmv'],
'max_size_kb' => 102400,
'dir' => 'video',
'default_preload' => 'metadata',
],
];
<?php
 
return [
'audio' => [
'extensions' => ['mp3', 'wav', 'ogg', 'm4a', 'aac', 'flac', 'webm'],
'max_size_kb' => 20480,
'dir' => 'audio',
'default_preload' => 'metadata',
],
 
'video' => [
'extensions' => ['mp4', 'mov', 'avi', 'mkv', 'webm', 'flv', 'wmv'],
'max_size_kb' => 102400,
'dir' => 'video',
'default_preload' => 'metadata',
],
];

Migration example

For storing audio and video in DB (string or json types):

Schema::table('posts', function (Blueprint $table) {
$table->string('audio')->nullable();
$table->json('audio_list')->nullable();
$table->string('video')->nullable();
$table->json('video_list')->nullable();
$table->json('video_list_posters')->nullable();
});
Schema::table('posts', function (Blueprint $table) {
$table->string('audio')->nullable();
$table->json('audio_list')->nullable();
$table->string('video')->nullable();
$table->json('video_list')->nullable();
$table->json('video_list_posters')->nullable();
});

Usage

Audio — single audio

Form:

  • File upload
  • showPreview(true) — player and preview (default)
  • showPreview(false) — filename only

Index:

  • Play button → modal with player
  • editOnIndex(true) — edit icon linking to form
  • downloadOnIndex(true) — download icon
  • downloadPreviewModal(true) — download button in modal
  • showFileName(bool) — show filename
use MoonShine\MediaFields\Fields\Audio;
 
Audio::make('Audio', 'audio')
->dir('uploads/audio')
->editOnIndex(true)
->downloadOnIndex(true)
->downloadPreviewModal(true)
->showFileName(true)
->preload('metadata')
->loop(false);
use MoonShine\MediaFields\Fields\Audio;
 
Audio::make('Audio', 'audio')
->dir('uploads/audio')
->editOnIndex(true)
->downloadOnIndex(true)
->downloadPreviewModal(true)
->showFileName(true)
->preload('metadata')
->loop(false);

Audio form Audio index


AudioList — multiple audio

Form:

  • Multiple file selection
  • maxFiles(int) — max count
  • maxFileSizeKb(int) — max size per file
  • showPreview(true) — player for each
  • maxHeightContainer(string) — container max-height (e.g. '400px')

Index:

  • Play button + count → modal with list
  • downloadOnIndex(true) — download for each file
use MoonShine\MediaFields\Fields\AudioList;
 
AudioList::make('Audio list', 'audio_list')
->dir('uploads/audio')
->maxFiles(10)
->maxFileSizeKb(5120)
->editOnIndex(true)
->downloadOnIndex(true)
->maxHeightContainer('400px');
use MoonShine\MediaFields\Fields\AudioList;
 
AudioList::make('Audio list', 'audio_list')
->dir('uploads/audio')
->maxFiles(10)
->maxFileSizeKb(5120)
->editOnIndex(true)
->downloadOnIndex(true)
->maxHeightContainer('400px');

Video — single video

Form:

  • Upload, preview with video player
  • poster(string) — static poster URL
  • posterField(Image $field) — poster as embedded Image field

Index:

  • With poster: thumbnail + play button
  • Without poster: camera icon
  • videoMaxHeight(string) — max-height for video in modal
use MoonShine\MediaFields\Fields\Video;
 
Video::make('Video', 'video')
->dir('uploads/video')
->poster('/images/poster.jpg')
->editOnIndex(true)
->videoMaxHeight('400px');
use MoonShine\MediaFields\Fields\Video;
 
Video::make('Video', 'video')
->dir('uploads/video')
->poster('/images/poster.jpg')
->editOnIndex(true)
->videoMaxHeight('400px');

With poster via separate column:

Video::make('Video', 'video')
->dir('uploads/video')
->posterColumn('video_poster')
->posterDir('uploads/posters');
Video::make('Video', 'video')
->dir('uploads/video')
->posterColumn('video_poster')
->posterDir('uploads/posters');

Video form Video index


VideoList — multiple video

Form:

  • Video carousel or grid
  • maxFiles, maxFileSizeKb
  • gridColumns(2|3|4|null) — 2–4 columns or null for carousel
  • posterField(VideoListPosters $field) — poster per video

Index:

  • Camera icon + count or poster thumbnails
  • videoMaxHeight(string), gridColumns(int|null)
use MoonShine\MediaFields\Fields\VideoList;
use MoonShine\MediaFields\Fields\VideoListPosters;
 
VideoList::make('Videos', 'videos')
->dir('uploads/videos')
->maxFiles(5)
->editOnIndex(true)
->videoMaxHeight('320px')
->gridColumns(2)
->posterField(
VideoListPosters::make('Posters', 'video_list_posters')
->videosColumn('videos')
);
use MoonShine\MediaFields\Fields\VideoList;
use MoonShine\MediaFields\Fields\VideoListPosters;
 
VideoList::make('Videos', 'videos')
->dir('uploads/videos')
->maxFiles(5)
->editOnIndex(true)
->videoMaxHeight('320px')
->gridColumns(2)
->posterField(
VideoListPosters::make('Posters', 'video_list_posters')
->videosColumn('videos')
);

VideoListPosters — posters for VideoList

Separate field for uploading posters for each video. Use with VideoList::posterField().

VideoListPosters::make('Video posters', 'video_list_posters')
->videosColumn('videos');
VideoListPosters::make('Video posters', 'video_list_posters')
->videosColumn('videos');

Example Resource

<?php
 
namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\MediaFields\Fields\Audio;
use MoonShine\MediaFields\Fields\AudioList;
use MoonShine\MediaFields\Fields\Video;
use MoonShine\MediaFields\Fields\VideoList;
use MoonShine\MediaFields\Fields\VideoListPosters;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
public function fields(): array
{
return [
Audio::make('Audio', 'audio')
->dir('uploads/audio')
->editOnIndex(true)
->downloadOnIndex(true),
 
AudioList::make('Audio list', 'audio_list')
->dir('uploads/audio')
->maxFiles(5),
 
Video::make('Video', 'video')
->dir('uploads/video')
->editOnIndex(true)
->videoMaxHeight('400px'),
 
VideoList::make('Videos', 'videos')
->dir('uploads/videos')
->maxFiles(5)
->gridColumns(2)
->posterField(
VideoListPosters::make('Posters', 'video_list_posters')
->videosColumn('videos')
),
];
}
}
<?php
 
namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\MediaFields\Fields\Audio;
use MoonShine\MediaFields\Fields\AudioList;
use MoonShine\MediaFields\Fields\Video;
use MoonShine\MediaFields\Fields\VideoList;
use MoonShine\MediaFields\Fields\VideoListPosters;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
public function fields(): array
{
return [
Audio::make('Audio', 'audio')
->dir('uploads/audio')
->editOnIndex(true)
->downloadOnIndex(true),
 
AudioList::make('Audio list', 'audio_list')
->dir('uploads/audio')
->maxFiles(5),
 
Video::make('Video', 'video')
->dir('uploads/video')
->editOnIndex(true)
->videoMaxHeight('400px'),
 
VideoList::make('Videos', 'videos')
->dir('uploads/videos')
->maxFiles(5)
->gridColumns(2)
->posterField(
VideoListPosters::make('Posters', 'video_list_posters')
->videosColumn('videos')
),
];
}
}

Themes and Styles

Uses MoonShine CSS variables:

  • --color-base, --color-base-text, --color-base-stroke
  • --color-primary, --color-primary-text

Supports light and dark themes via .dark and [data-theme="dark"].


Troubleshooting

403 Forbidden when playing audio/video

Server may block MIME types. Check:

  1. Apache.htaccess or config:
AddType audio/mpeg .mp3
AddType video/mp4 .mp4
AddType audio/mpeg .mp3
AddType video/mp4 .mp4
  1. ModSecurity — disable or adjust rules for media files.

  2. Nginx — ensure types includes required MIME types.

Clear cache after update

php artisan config:clear
php artisan view:clear
php artisan config:clear
php artisan view:clear

License

MIT. See LICENSE.