goodappr / moonshine-media-fields
Audio, AudioList, Video, VideoList fields for MoonShine 4.x - media with preview and modals
Package info
github.com/GoodAppR/moonshine-media-fields
Language:Blade
pkg:composer/goodappr/moonshine-media-fields
Requires
- php: ^8.2
- moonshine/moonshine: ^4.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Audio, AudioList, Video and VideoList fields for MoonShine 4.x with preview, playback modals and custom audio player.
Table of Contents
Requirements
- PHP 8.2+
- Laravel 11+
- MoonShine 4.x
- Alpine.js (included with MoonShine)
Installation
composer require goodappr/moonshine-media-fields
The package auto-registers MediaFieldsServiceProvider.
Configuration
Publish config (optional)
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', ], ];
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(); });
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 formdownloadOnIndex(true)— download icondownloadPreviewModal(true)— download button in modalshowFileName(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);
AudioList — multiple audio
Form:
- Multiple file selection
maxFiles(int)— max countmaxFileSizeKb(int)— max size per fileshowPreview(true)— player for eachmaxHeightContainer(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');
Video — single video
Form:
- Upload, preview with video player
poster(string)— static poster URLposterField(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');
With poster via separate column:
Video::make('Video', 'video') ->dir('uploads/video') ->posterColumn('video_poster') ->posterDir('uploads/posters');
VideoList — multiple video
Form:
- Video carousel or grid
maxFiles,maxFileSizeKbgridColumns(2|3|4|null)— 2–4 columns ornullfor carouselposterField(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') );
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');
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') ), ]; } }
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:
- Apache —
.htaccessor config:
AddType audio/mpeg .mp3 AddType video/mp4 .mp4
-
ModSecurity — disable or adjust rules for media files.
-
Nginx — ensure
typesincludes required MIME types.
Clear cache after update
php artisan config:clear php artisan view:clear
License
MIT. See LICENSE.




