Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Medialibrary Extensions Laravel Package

mlbrgn/laravel-medialibrary-extensions

A collection of extensions for spatie/laravel-medialibrary that adds extra helpers and functionality for managing media in Laravel applications, streamlining common upload, conversion, and storage tasks with additional tools and integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

This package layers extra behaviour on top of spatie/laravel-medialibrary — it does not replace it. Before touching it, make sure the base package is installed, migrated (php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations" then migrate), and that your models already implement HasMedia with the InteractsWithMedia trait.

Where to look first:

  1. config/medialibrary-extensions.php (publish with php artisan vendor:publish --tag="medialibrary-extensions-config") — this is where the package's opinions live; read it before writing any code.
  2. The package's own Media model / model extensions — check composer.json and the service provider to see what it registers into the container and into the morph map.
  3. The host app's existing Relation::enforceMorphMap() / Relation::morphMap() call in a service provider — this is the integration point most likely to bite you (see Gotchas).

A good first use case: take an existing Post model with a registerMediaCollections() method, add a single-file collection, and confirm the package's helpers (conversion/URL/collection utilities) resolve correctly against it. That validates the whole chain — config, morph map, filesystem, conversions — in one pass.

Minimum viable setup:

composer require mlbrgn/laravel-medialibrary-extensions
php artisan vendor:publish --tag="medialibrary-extensions-config"
php artisan migrate
// app/Models/Post.php
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Post extends Model implements HasMedia
{
    use InteractsWithMedia;

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('cover')->singleFile();
    }
}

Implementation Patterns

Keep the base package as the source of truth. Use Spatie's addMediaCollection(), registerMediaConversions(), and getFirstMediaUrl() as normal, and let this package extend behaviour around them. Don't invent a parallel API — it makes future upgrades of either package painful.

Centralise collection definitions. If several models share a "gallery" or "cover" concept, define the collection setup in a trait or base model so conversions and accepted MIME types stay consistent:

trait HasCoverImage
{
    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('cover')
            ->singleFile()
            ->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp']);
    }

    public function registerMediaConversions(Media $media = null): void
    {
        $this->addMediaConversion('thumb')->width(320)->nonQueued();
        $this->addMediaConversion('large')->width(1600)->queued();
    }
}

Queue conversions in production, never in tests. Use ->nonQueued() only for the small derivatives you need synchronously (thumbnails in an index view). Everything else should go through the queue so uploads stay fast — pair this with php artisan queue:work in dev, and remember conversion jobs need the media record committed first, so avoid wrapping uploads in a transaction that hasn't committed.

Form upload flow. The reliable pattern is: validate the upload in a FormRequest, store the parent model, then addMediaFromRequest('cover')->toMediaCollection('cover'). If you're using Livewire, use WithFileUploads with temporary uploads and move media in the updated/saving hook rather than mid-render.

Responsive/image markup. Rather than hand-rolling <picture> tags, use the package's URL/srcset helpers where provided, and fall back to getUrl('thumb') / getSrcset() from the base package. Wrap this in a Blade component so view code never touches media models directly:

<x-media-image :media="$post->getFirstMedia('cover')" conversion="thumb" />

API resources. Serialise media through an JsonResource (MediaResource) that exposes url, thumb, srcset, and mime_type — keeps storage paths and internal model IDs out of your public contract.

Multi-tenancy / multiple disks. If tenants need isolated storage, register a per-tenant disk in registerMediaDisk() on the model or via a global disk resolver in a service provider. Test disk switching explicitly; it's the most common source of "file uploaded but 404" reports.

Morph map discipline. If you use Relation::enforceMorphMap(), do it early (a dedicated AppServiceProvider::boot() or a MorphMapServiceProvider registered before anything else) and include every model that has media, plus any model this package registers. See Gotchas for why this matters more as of 2.8.12.

Gotchas and Tips

Morph map collisions (fixed in 2.8.12). Prior to 2.8.12 the package's registered model aliases could collide with aliases your application had already claimed in Relation::morphMap() / enforceMorphMap(), producing wrong-class resolution, silent null morphs, or Class not found errors when hydrating media records. Upgrade to ^2.8.12 — this is a straight bug fix with no API changes. After upgrading:

  • Clear caches: php artisan config:clear && php artisan cache:clear && php artisan optimize:clear.
  • If you had worked around the collision by aliasing your own models around the package's names, remove the workaround before upgrading, or you'll now have the inverse problem.
  • Existing rows keep whatever model_type string was written. Check select distinct model_type from media; — if any values look like they were written under a collision, you may need a small data migration to correct them.
  • Keep your morph map in one place, and add a test that asserts Relation::getMorphedModel($alias) returns the class you expect for every alias you register.

enforceMorphMap is strict by design. Once enforced, models without an alias throw rather than falling back to FQCNs. If you add a new mediable model and forget the alias, media attaching fails at runtime, often only on the store() path — easy to miss because reads of existing records still work.

Config caching. The published config is loaded from config/; if you change it and see no effect, you're almost certainly running with a cached config (bootstrap/cache/config.php). php artisan config:clear is the first debugging step for "config change ignored".

Storage links and disks. php artisan storage:link is required for the public disk. If URLs 404 in production but work locally, compare FILESYSTEM_DISK, the model's registerMediaDisk(), and whether the symlink exists in the deployed release directory (some deploy scripts wipe it — add storage:link to the deploy hook, guarded with --force where appropriate).

Queued conversions and nonQueued confusion. A conversion defined with ->queued() won't exist immediately after upload; getUrl('thumb') will fall back to the original unless you check hasGeneratedConversion() or use getUrl('thumb') with a fallback. Guard your Blade components accordingly, or mark the small derivative nonQueued().

Image driver. Conversions need GD or Imagick. Imagick is required for some format handling (notably SVG/PDF derivatives). Check php -m in the same PHP binary that runs the queue worker — a mismatch between web and worker can make conversions pass in the browser and fail in the queue.

Extending vs. editing vendor code. If you need to alter how the package's models behave, subclass and rebind in the container (or via the package's config), never edit vendor/. Composer will overwrite it, and the diff gets lost.

Debugging tips. php artisan tinker then $post->getMedia('cover')->map->getUrl() is the fastest way to isolate whether the problem is storage, conversions, or your view layer. tail -f storage/logs/laravel.log plus failed_jobs (php artisan queue:failed) catches conversion failures. Media::find($id)->getPath() confirms the file exists where the DB says it should.

Upgrade hygiene. This is a patch release sitting on top of Spatie's medialibrary, which has had breaking majors. Pin both packages with caret constraints, read the Spatie upgrade guide before bumping it, and run your media test suite (upload, conversion, delete, morph resolution) after any bump in either package.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager