Image Variants
How Contensio automatically generates resized and cropped versions of uploaded images — and how to configure sizes per content type.
When you upload an image, Contensio queues a background job that generates multiple resized copies — called variants — based on the image size configuration of each content type. Variants are always saved as WebP for optimal file size and quality.
Why variants exist
A 4 MB original photo shouldn't be sent to a mobile visitor loading a 300 px thumbnail. Variants let your theme serve the right size for every context — thumbnails in listing pages, full-width images in post headers, OG images for social shares — without any resizing at request time.
Default size presets
Contensio ships with six size presets. Each content type can activate or deactivate them independently and override their dimensions.
| Key | Label | Default size | Fit | Active by default |
|---|---|---|---|---|
small |
Small | 480 × 320 | Cover | All content types |
medium |
Medium | 900 × 600 | Cover | All content types |
large |
Large | 1600 × 900 | Cover | All content types |
og |
OG Image | 1200 × 630 | Cover | Post, Page |
thumbnail |
Thumbnail | 150 × 150 | Pad | None (opt-in) |
square |
Square | 600 × 600 | Pad | None (opt-in) |
Configuring image sizes per content type
Each content type has its own Image Sizes tab in its edit form (Configuration → Content Types → edit). There you can, for each preset:
- Enable or disable the variant for this type.
- Change the width and height to match your theme's layout.
- Change the fit mode and quality.
Changes are saved immediately. After saving, Contensio queues a regeneration job for all existing images so variants are updated to the new dimensions.
Fit modes explained
The fit mode controls how the source image is transformed to reach the target dimensions.
| Mode | Behaviour | Best for |
|---|---|---|
| Cover | Scales the image up/down and crops the edges so the canvas is filled exactly. No empty space, no distortion. | Hero images, featured images, cards |
| Contain | Scales the image to fit entirely within the box. Aspect ratio is preserved; empty space may appear if the image ratio differs from the target. | Logos, icons |
| Scale | Stretches or squashes the image to the exact dimensions. Distorts if the aspect ratios differ. | Rarely useful — prefer cover or contain |
| Crop | Hard-crops the image from the centre to the exact dimensions without scaling. | When you need a pixel-perfect extract of the centre |
| Pad | Like contain, but fills the empty space with the configured background colour. Produces an image that is exactly width × height with the subject centred. | Square thumbnails, product images on white |
Quality
All variants are encoded at the configured quality level (default: 85). Valid range is 1–100. Higher values produce larger files with more detail; lower values produce smaller files with more compression artefacts. 85 is a good default for photographic content.
Background colour
Only applies when fit is Pad. Sets the fill colour for the empty space. Default is #ffffff (white). Use a hex colour, e.g. #f3f4f6 for a light grey.
How variants are stored
Variants are stored alongside the original file on the same disk, in the same folder. The filename pattern is:
{original_basename}_{size_key}.webp
For example, if the original is uploads/2026/04/photo.jpg and the medium variant is active, the variant is stored at:
uploads/2026/04/photo_medium.webp
A media_variants record is created for each variant, linked to the original media record.
Variants across content types
Variants are generated using the union of all active sizes across all content types. If even one content type has the thumbnail size active, every uploaded image will get a _thumbnail.webp variant — regardless of which content type the image is used in.
This means activating a size on a content type affects all future uploads, not just images assigned to that type.
Regenerating variants manually
If you change image size settings after images are already uploaded, Contensio automatically queues regeneration jobs on save. If your queue is not running or you need to force regeneration, dispatch the job manually from Tinker:
use Contensio\Models\Media;
use Contensio\Jobs\ProcessMediaVariants;
Media::whereNotNull('width')->each(fn ($m) => ProcessMediaVariants::dispatch($m));
Make sure your queue worker is running:
php artisan queue:work
Adding custom size presets
The built-in presets are defined in config/contensio.php under image_sizes. To add a custom preset, publish the config and add an entry:
php artisan vendor:publish --tag=contensio-config
Then in config/contensio.php:
'image_sizes' => [
// ... existing presets ...
'hero' => [
'label' => 'Hero',
'width' => 1920,
'height' => 800,
'fit' => 'cover',
'quality' => 90,
'background' => '#000000',
'default_for' => ['post'], // active by default for posts only
],
],
The new preset appears in the Image Sizes tab for all content types.
Using variants in themes
The Media model exposes its variants via the variants relationship. Each MediaVariant has size_key, path, width, height, and file_size.
$image = $content->featuredImage; // Media model
// Get a specific variant URL
$variant = $image->variants->firstWhere('size_key', 'medium');
$url = Storage::disk($image->disk)->url($variant->path);
// Or fall back to the original if the variant doesn't exist
$url = $variant
? Storage::disk($image->disk)->url($variant->path)
: Storage::disk($image->disk)->url($image->file_path);