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:
| Model | Bucket (config key) | Shape | Helpers |
|---|---|---|---|
Product | media.featured_bucket (featured) | Single file | featuredImage(), featuredImageUrl() |
Product | media.gallery_bucket (gallery) | Multiple files | galleryImages(), galleryUrls(), seoImageUrl() |
ProductVariant | media.variant_bucket (gallery) | Multiple files | variantImages(), variantImageUrl(), variantImageUrls() |
Category | media.banner_bucket (banner) | Single file | banner(), 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> tagEvery 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 cryptoBy 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.