NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Shops for Laravel

Product media

Products, variants and categories carry images via media-library-for-laravel. Catalog media is public by default (CDN- and SEO-friendly) and generates responsive widths from shops.media.responsive_widths. Every bucket accepts JPEG, PNG, WebP, GIF and AVIF:

ModelBucket (config key)ShapeHelpers
Productmedia.featured_bucket (featured)Single filefeaturedImage(), featuredImageUrl()
Productmedia.gallery_bucket (gallery)Multiple filesgalleryImages(), galleryUrls(), seoImageUrl()
ProductVariantmedia.variant_bucket (gallery)Multiple filesvariantImages(), variantImageUrl(), variantImageUrls()
Categorymedia.banner_bucket (banner)Single filebanner(), bannerUrl()
$product->addMedia($file)->toMediaBucket($product->featuredBucket());   // single featured image
$product->addMedia($file)->toMediaBucket($product->galleryBucket());    // multi-image gallery

$product->featuredImage();                      // ?Media
$product->featuredImageUrl();                   // original URL ('' when empty)
$product->featuredImageUrl('responsive-640');   // a responsive width
$product->galleryImages();                      // Collection<Media>
$product->galleryUrls('responsive-320');        // list<string>
$product->seoImageUrl();                        // featured, else the first gallery image, else ''

$variant->addMedia($file)->toMediaBucket($variant->variantGalleryBucket());
$variant->variantImages();                      // Collection<Media>
$variant->variantImageUrl();                    // first variant image URL ('')
$variant->variantImageUrls();                   // list<string>

$category->addMedia($file)->toMediaBucket($category->bannerBucket());
$category->banner();                            // ?Media
$category->bannerUrl();                         // string ('')

Responsive images

The buckets declare no named variants — each ladder width is generated as a variant named responsive-{width} (never upscaled past the original). Use media-library’s srcset helpers for markup:

$image = $product->featuredImage();

$image?->srcset();   // "… 320w, … 640w, …" — generated widths only, ascending
$image?->responsiveImage('', ['alt' => 'Sparkling Water', 'sizes' => '100vw']);   // a full <img> tag

Every reader takes an optional variant name and serves the original image when that variant has not been generated (an image narrower than the width, or a queued conversion that has not run yet), so a page never fails on a missing variant. Bucket names, disk, visibility, responsive widths and the optional max file size (bytes) are configured under shops.media and apply to every catalog bucket — product, variant and category alike. Media rows live in media-library’s own media table, linked polymorphically.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.