Native bouwenBuild
Meerdere foto's per variant in Shopify, zonder app en zonder losse producten
Diek Thunnissen22 sep 202612 min leestijd
Shopify hangt maar één afbeelding aan een variant. Wie per kleur een hele fotoset wil, maakt van elke kleur een los product of installeert een app. Met één variant-metafield en een klein snippet doet je eigen theme het zelf. De code voor Dawn en Horizon staat hieronder.

Bij kledingmerken kom ik het steeds tegen. Een trui in ecru en antraciet, per kleur een paar foto's. Shopify laat je per variant 1 afbeelding kiezen. Kiest de klant antraciet, dan springt de galerij naar die ene foto, en daarna swipet hij gewoon door de ecru-foto's heen.
De twee oplossingen die ik meestal zie zijn allebei niet lekker. Van elke kleur een los product maken geeft je twee urls, twee voorraden en reviews die uit elkaar vallen. Een app die het regelt kost een abonnement en hangt een eigen galerij in je theme, met een eigen slider, eigen zoom en eigen bugs.
Dus hebben we het native gebouwd. Eén variant-metafield met de foto's die bij die kleur horen, en een snippet dat de productmedia daarop filtert. Je theme rendert de galerij zoals altijd, alleen komen er andere media doorheen. Slider, zoom en thumbnails blijven van je theme. Het blijft 1 product, dus 1 url en al je reviews bij elkaar.

Hoe het werkt
Alle foto's blijven gewone productmedia. Op de variant zet je een metafield met de foto's die bij die variant horen. Bij elke variantwissel rendert het theme de galerij opnieuw en filtert het snippet de productmedia op die lijst. Matchen gaat op bestandsnaam, dus je kiest in het metafield de foto's die al bij het product staan en je uploadt geen losse kopie.

Maten van dezelfde kleur delen de set, dus je vult het 1 keer per kleur in. Een variant zonder set toont alle productmedia, zoals nu. De gewone variant-afbeelding blijft altijd vooraan staan. En opent iemand de pagina via ?variant=123 vanuit een ad, een feed of een mail, dan staat direct de juiste set er.
Wat je nodig hebt
Toegang tot de theme-code (Online Store, Themes, Edit code), een kwartier voor Horizon of een half uur voor Dawn, en per kleur een paar foto's die al bij het product staan. Je hoeft geen developer te zijn, maar je moet wel een stukje code kunnen plakken op de plek die hieronder staat. Twijfel je, stuur dit dan door naar degene die je theme beheert.
Werk in een kopie. Ga naar Online Store, Themes, klik op de drie puntjes bij je live theme en kies Duplicate. Doe alle stappen in die kopie. Je live shop merkt er niks van tot je de kopie publiceert, en als er iets misgaat gooi je hem gewoon weg.
Stap 1: metafield aanmaken
Ga naar Settings, Custom data, Variants en klik op Add definition. Naam: Variant afbeeldingen. Namespace en key: custom.variant_images. Type: File, list of files. Zet Storefront access aan, anders kan het theme het veld niet lezen.
Check: open een willekeurig product, klik op een variant en scroll naar beneden. Onder Metafields staat nu een veld Variant afbeeldingen.
Stap 2: foto's toewijzen
Upload alle foto's gewoon bij het product. Open daarna een variant, klik in het metafield op Select files en kies de foto's van die kleur. Dit hoeft maar bij 1 variant per kleur. Laat ook de normale variant-afbeelding ingesteld staan, want die gebruikt Shopify in de cart en de checkout, en Dawn heeft hem nodig om de galerij te verversen.
Begin met 1 product om te testen. Neem een trui in Ecru en Antraciet, maten S tot en met XL. Bij Ecru / S vul je het metafield met de drie ecru-foto's, bij Antraciet / S met de drie antraciet-foto's. De andere zes varianten laat je leeg, die nemen de set van hun kleur over.
Check: het metafield toont kleine previews van de gekozen foto's. Staat er een foto tussen die je net los hebt geüpload in plaats van gekozen uit het product, haal die er dan uit. Die matcht straks niet op bestandsnaam.
Stap 3: het gedeelde snippet
Maak snippets/variant-media-files.liquid aan. Dit bestand is voor elk theme hetzelfde. Het geeft de bestandsnamen terug van de media die bij de gekozen variant horen, gescheiden door een verticale streep. Blijft het leeg, dan filtert het theme niet en zie je alle productmedia.
42 regels codeToon code +Verberg code −
{%- comment -%}
Geeft de bestandsnamen terug van de media die bij de gekozen variant horen, gescheiden door |.
Leeg = geen filter, het theme toont dan alle productmedia.
Gebruik:
{%- capture vm_files -%}{%- render 'variant-media-files', product: product, option_position: 1 -%}{%- endcapture -%}
{%- assign vm_files = vm_files | strip | split: '|' -%}
option_position = de positie van de optie waar de foto's aan hangen (meestal kleur).
{%- endcomment -%}
{%- liquid
assign option_index = option_position | default: 1 | minus: 1
assign vm_variant = product.selected_or_first_available_variant
assign vm_set = vm_variant.metafields.custom.variant_images.value
if vm_set == blank
for sibling in product.variants
if sibling.options[option_index] == vm_variant.options[option_index] and sibling.metafields.custom.variant_images.value != blank
assign vm_set = sibling.metafields.custom.variant_images.value
break
endif
endfor
endif
if vm_set != blank
assign product_files = ''
for media in product.media
assign file = media.preview_image | image_url: width: 100 | split: '/' | last | split: '?' | first
assign product_files = product_files | append: file | append: '|'
endfor
assign product_files = product_files | split: '|'
for item in vm_set
assign source = item.preview_image | default: item
assign file = source | image_url: width: 100 | split: '/' | last | split: '?' | first
if product_files contains file
echo file
echo '|'
endif
endfor
endif
-%}Het snippet geeft alleen bestandsnamen terug die ook echt bij het product staan. Matcht er niks, dan blijft het leeg en zie je gewoon alles. Een lege galerij kan dus niet.
Stap 4a: Horizon
Dit geldt voor Horizon en de themes die erop gebouwd zijn. Horizon vervangt bij een variantwissel de hele galerij door de nieuwe server-render, dus hier is alleen Liquid nodig.
Open snippets/product-media-gallery-content.liquid en zoek de regel met assign has_image_drop. Zet dit blok er direct boven, binnen dezelfde liquid-tag.
capture vm_files
render 'variant-media-files', product: selected_product, option_position: 1
endcapture
assign vm_files = vm_files | strip | split: '|'
if vm_files.size > 0
assign vm_sorted = '' | split: ','
for media in sorted_media
assign vm_file = media.preview_image | image_url: width: 100 | split: '/' | last | split: '?' | first
if media.id == selected_variant_media.id or vm_files contains vm_file
assign vm_match = selected_product.media | where: 'id', media.id
assign vm_sorted = vm_sorted | concat: vm_match
endif
endfor
assign sorted_media = vm_sorted
endifKlaar. Slideshow, grid, thumbnails en zoom lezen allemaal uit sorted_media, dus die gaan vanzelf mee. De theme-instelling Hide unselected variant media mag aan of uit staan.
Stap 4b: Dawn
Dit geldt voor Dawn en de afgeleiden zoals Craft, Sense, Refresh en Studio. Dawn ververst bij een variantwissel alleen de grote foto's en de zoom-modal vanuit de nieuwe server-render. De thumbnails niet. Daarom drie kleine Liquid-aanpassingen en een stukje JS.
1. Open snippets/product-media-gallery.liquid en zet dit bovenaan, direct onder het comment-blok.
{%- capture vm_files -%}{%- render 'variant-media-files', product: product, option_position: 1 -%}{%- endcapture -%}
{%- assign vm_files = vm_files | strip | split: '|' -%}2. In hetzelfde bestand, in de eerste for media in product.media loop. Zet dit direct onder het bestaande blok dat eindigt op continue en endif.
{%- if vm_files.size > 0 -%}
{%- assign vm_file = media.preview_image | image_url: width: 100 | split: '/' | last | split: '?' | first -%}
{%- unless vm_files contains vm_file -%}{%- continue -%}{%- endunless -%}
{%- endif -%}3. Open snippets/product-media-modal.liquid. Zet de twee regels van punt 1 bovenaan, en het blok van punt 2 als eerste regel binnen de for media in product.media loop. Zo toont ook de zoom alleen de gekozen set.
4. De thumbnails. Zet dit onderaan snippets/product-media-gallery.liquid. Het luistert naar de variantChange-event van Dawn en verbergt de thumbnails die niet in de galerij staan.
<script>
document.addEventListener('DOMContentLoaded', function () {
function syncThumbnails() {
document.querySelectorAll('media-gallery').forEach(function (gallery) {
var viewer = gallery.querySelector('[id^="GalleryViewer"]');
var thumbnails = gallery.querySelector('[id^="GalleryThumbnails"]');
if (!viewer || !thumbnails) return;
var visible = new Set();
viewer.querySelectorAll('li[data-media-id]').forEach(function (item) {
visible.add(item.dataset.mediaId);
});
thumbnails.querySelectorAll('li[data-target]').forEach(function (thumb) {
thumb.style.display = visible.has(thumb.dataset.target) ? '' : 'none';
});
if (typeof thumbnails.resetPages === 'function') thumbnails.resetPages();
});
}
syncThumbnails();
if (typeof subscribe === 'function' && typeof PUB_SUB_EVENTS !== 'undefined') {
subscribe(PUB_SUB_EVENTS.variantChange, syncThumbnails);
}
});
</script>Let op bij Dawn: een variant zonder eigen variant-afbeelding ververst de galerij niet. Dat zit in Dawn zelf. Geef dus elke variant ook gewoon z'n normale afbeelding.
Stap 5: testen
Open de preview van je kopie-theme en ga naar het product dat je in stap 2 hebt gevuld. Kies de eerste kleur, je ziet alleen de foto's van die kleur met de variant-afbeelding vooraan. Wissel naar de andere kleur, de grote foto's en de thumbnails wisselen allebei mee. Wissel van maat binnen dezelfde kleur, de set blijft staan.
Open daarna de zoom of lightbox, ook daar staan alleen de foto's van de gekozen kleur. Kopieer de url met ?variant= erin en open hem in een nieuw tabblad, de pagina opent direct met de juiste set. Open een product waar je niks hebt ingevuld, dat ziet er precies zo uit als voorheen. Doe hetzelfde nog een keer op je telefoon.
Klopt alles, publiceer dan de kopie en vul de rest van je producten.
Werkt het niet?
Je ziet nog steeds alle foto's. Meestal matcht de bestandsnaam niet. De foto in het metafield moet hetzelfde bestand zijn als de foto bij het product. Haal hem uit het metafield en kies hem opnieuw via Select files, zoek op de naam van de productfoto. Check ook of de namespace en key exact custom.variant_images zijn.
De galerij wisselt pas na een refresh (Dawn). De variant heeft geen eigen variant-afbeelding. Stel die in bij elke variant.
De thumbnails wisselen niet mee (Dawn). Het script uit punt 4 staat er niet of staat in het verkeerde bestand. Het hoort onderaan snippets/product-media-gallery.liquid.
De verkeerde optie bepaalt de set. Staat kleur bij jou als tweede optie, bijvoorbeeld Maat en dan Kleur, zet dan option_position: 2 in de render-regel.
Liquid error in de preview. Bijna altijd een blok dat buiten de liquid-tag (Horizon) of buiten de for-loop (Dawn) is geplakt. Vergelijk de plek nog een keer met de stap.
Veel producten vullen
Met de hand is prima tot een stuk of vijftig producten. Daarboven wil je het in bulk doen, met Matrixify (een kolom voor het variant-metafield) of met een scriptje op de Admin API via metafieldsSet met de MediaImage-id's van de productfoto's. Je hoeft per kleur maar 1 variant te vullen, dat scheelt al snel driekwart van het werk.
Ander theme?
Het principe is overal hetzelfde. Render het gedeelde snippet, en sla in de loop over je productmedia alles over wat niet in vm_files staat (het blok van Dawn punt 2). Rendert je theme de galerij opnieuw bij een variantwissel, dan ben je klaar. Doet hij dat niet, dan moet je de galerij zelf verversen met de Section Rendering API.
Goed om te weten
Zodra een variant een set heeft, zie je alleen wat in die set zit. Dat geldt ook voor video's en 3D-modellen. Wil je een video bij elke kleur, zet hem dan in elke set.
Bij producten met honderden varianten wordt de fallback, het zoeken naar een variant met dezelfde kleur, zwaarder. Vul het metafield dan op elke variant in.
Productkaarten in collecties en quick add laat dit ongemoeid. En na een theme-update moet je de aanpassingen opnieuw doen. Het zijn er weinig, maar noteer ze even.
Wil je dat wij dit voor je inrichten, of loop je ergens vast? Stuur even een bericht, dan kijken we mee.
Veelgestelde vragen.
- Heb ik Shopify Plus nodig?
- Nee. Variant-metafields, Liquid en de theme-code-editor zitten in elk plan vanaf Basic. Het enige wat je nodig hebt is een theme waarvan je de code mag aanpassen, en dat geldt voor elk theme uit de Theme Store.
- Werkt dit ook met een theme dat niet op Dawn of Horizon is gebouwd?
- Het snippet uit stap 3 werkt overal. De inbouw verschilt per theme: je zoekt de loop over de productmedia in de galerij en slaat daar alles over wat niet in de lijst staat. Rendert je theme de galerij opnieuw bij een variantwissel, dan ben je klaar. Zo niet, dan moet je die render zelf triggeren via de Section Rendering API. Dat is meestal een uurtje werk voor wie je theme beheert.
- Wat gebeurt er met de foto's in de cart, de checkout en collecties?
- Niks. Die gebruiken de gewone variant-afbeelding die je in Shopify instelt, en die laat je gewoon staan. Het metafield stuurt alleen de galerij op de productpagina aan.
- Waarom niet gewoon per kleur een los product?
- Dat kan, en voor sommige shops is het de betere keuze, bijvoorbeeld als elke kleur een eigen naam en eigen SEO-pagina moet hebben. Maar je krijgt er ook aparte urls, aparte voorraden en losse reviews van, en de klant moet naar een andere pagina om van kleur te wisselen. Met het metafield houd je één product en wissel je alleen de foto's.
- Blijft dit werken na een update van mijn theme?
- Het metafield en het gedeelde snippet blijven staan. De regels die je in de galerij-bestanden van het theme hebt gezet, gaan bij een theme-update verloren en moet je opnieuw plakken. Het zijn drie kleine blokken, dus noteer waar ze staan.
Diek ThunnissenFounder & lead developer. Bouwt, verbetert en migreert de Shopify-laag voor DTC- en B2B-merken. LinkedInPlan een gesprek →

