Blog
Author: Sonya
12-24-2024 8:44 AMRecently, a Shopify store owner approached us with a specific requirement: they wanted to showcase only the images of the selected variant in their product gallery. This need arose from having multiple variants for a single product, each with its own set of images. By displaying only the relevant images, the store owner aimed to streamline the user experience, allowing customers to focus on the variant they were interested in without distraction.
Benefits of Displaying Only Selected Variant Images
Implementing this feature can significantly enhance your store's functionality and user experience. Here are some key advantages:
Improved User Experience: Customers can easily view and compare images of the selected variant without being overwhelmed by irrelevant images.
Enhanced Visual Appeal: A cleaner and more organized product gallery makes your store visually appealing, encouraging customers to explore further.
Increased Conversion Rates: Simplifying product presentation helps customers make informed purchasing decisions, potentially boosting conversion rates.
Steps to Implement Selected Variant Images in Shopify
Before making any code modifications, always ensure you create a copy of the theme first. Test all your changes on this copy to confirm everything works perfectly before publishing it to the live theme. This precaution helps prevent any issues from affecting your main theme and keeps your work safe.
To display only the images of the selected variant in your Shopify store, follow these straightforward steps:
Access Your Theme Code Editor: Log into your Shopify admin panel and navigate to "Online Store" > "Themes." Click on "Actions" and select "Edit code" for your active theme.
Modify
sections/main-product.liquid
: Open thesections/main-product.liquid
file. Add below code to the file., { "type": "header", "content": "Selected Variant Images" }, { "type": "paragraph", "content": "Subscribe our channel [Shinetech ChangChun](https:\/\/youtube.com\/@ShinetechShopidev?sub_confirmation=1)" }, { "type": "checkbox", "id": "enable_group_media", "label": "Enable Selected Variant Images", "default": false }
Update
snippets/product-media-gallery.liquid
: Locate and open thesnippets/product-media-gallery.liquid
file. Replace the existing code with code below.{% comment %} Renders a product media gallery. Should be used with 'media-gallery.js' Also see 'product-media-modal' Accepts: - product: {Object} Product liquid object - variant_images: {Array} Product images associated with a variant - limit: {Number} (optional) When passed, limits the number of media items to render Usage: {% render 'product-media-gallery' %} {% endcomment %} {%- liquid if section.settings.hide_variants and variant_images.size == product.media.size assign single_media_visible = true endif if limit == 1 assign single_media_visible = true endif assign media_count = product.media.size if section.settings.hide_variants and media_count > 1 and variant_images.size > 0 assign media_count = media_count | minus: variant_images.size | plus: 1 endif if media_count == 1 or single_media_visible assign single_media_visible_mobile = true endif if media_count == 0 or single_media_visible_mobile or section.settings.mobile_thumbnails == 'show' or section.settings.mobile_thumbnails == 'columns' and media_count < 3 assign hide_mobile_slider = true endif if section.settings.media_size == 'large' assign media_width = 0.65 elsif section.settings.media_size == 'medium' assign media_width = 0.55 elsif section.settings.media_size == 'small' assign media_width = 0.45 endif -%} <media-gallery id="MediaGallery-{{ section.id }}" role="region" {% if section.settings.enable_sticky_info %} class="product__column-sticky" {% endif %} aria-label="{{ 'products.product.media.gallery_viewer' | t }}" data-desktop-layout="{{ section.settings.gallery_layout }}" > <div id="GalleryStatus-{{ section.id }}" class="visually-hidden" role="status"></div> <slider-component id="GalleryViewer-{{ section.id }}" class="slider-mobile-gutter"> <a class="skip-to-content-link button visually-hidden quick-add-hidden" href="#ProductInfo-{{ section.id }}"> {{ 'accessibility.skip_to_product_info' | t }} </a> <ul id="Slider-Gallery-{{ section.id }}" class="product__media-list contains-media grid grid--peek list-unstyled slider slider--mobile" role="list" > {%- if product.selected_or_first_available_variant.featured_media != null -%} {%- assign featured_media = product.selected_or_first_available_variant.featured_media -%} <li id="Slide-{{ section.id }}-{{ featured_media.id }}" class="product__media-item grid__item slider__slide is-active{% if single_media_visible %} product__media-item--single{% endif %}{% if featured_media.media_type != 'image' %} product__media-item--full{% endif %}{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--fade-in{% endif %}" data-media-id="{{ section.id }}-{{ featured_media.id }}" > {%- assign media_position = 1 -%} {% render 'product-thumbnail', media: featured_media, media_count: media_count, position: media_position, desktop_layout: section.settings.gallery_layout, mobile_layout: section.settings.mobile_thumbnails, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true, media_width: media_width, media_fit: section.settings.media_fit, constrain_to_viewport: section.settings.constrain_to_viewport, lazy_load: false %} </li> {%- endif -%} {%- for media in product.media -%} {% if media_position >= limit or media_position >= 1 and section.settings.hide_variants and variant_images contains media.src %} {% continue %} {% endif %} {%- unless media.id == product.selected_or_first_available_variant.featured_media.id -%} {%- liquid assign media_position = media_position | default: 0 | plus: 1 assign lazy_load = false if media_position > 1 assign lazy_load = true endif assign current_color = product.selected_or_first_available_variant.option1 -%} {% if section.settings.enable_group_media == false or media_count == 1 or current_color == media.alt and section.settings.enable_group_media == true %} <li id="Slide-{{ section.id }}-{{ media.id }}" class="product__media-item grid__item slider__slide{% if single_media_visible %} product__media-item--single{% endif %}{% if product.selected_or_first_available_variant.featured_media == nil and forloop.index == 1 %} is-active{% endif %}{% if media.media_type != 'image' %} product__media-item--full{% endif %}{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--fade-in{% endif %}" data-media-id="{{ section.id }}-{{ media.id }}" > {% render 'product-thumbnail', media: media, media_count: media_count, position: media_position, desktop_layout: section.settings.gallery_layout, mobile_layout: section.settings.mobile_thumbnails, loop: section.settings.enable_video_looping, modal_id: section.id, xr_button: true, media_width: media_width, media_fit: section.settings.media_fit, constrain_to_viewport: section.settings.constrain_to_viewport, lazy_load: lazy_load %} </li> {% endif %} {%- endunless -%} {%- endfor -%} </ul> <div class="slider-buttons quick-add-hidden{% if hide_mobile_slider %} small-hide{% endif %}"> <button type="button" class="slider-button slider-button--prev" name="previous" aria-label="{{ 'general.slider.previous_slide' | t }}" > {% render 'icon-caret' %} </button> <div class="slider-counter caption"> <span class="slider-counter--current">1</span> <span aria-hidden="true"> / </span> <span class="visually-hidden">{{ 'general.slider.of' | t }}</span> <span class="slider-counter--total">{{ media_count }}</span> </div> <button type="button" class="slider-button slider-button--next" name="next" aria-label="{{ 'general.slider.next_slide' | t }}" > {% render 'icon-caret' %} </button> </div> </slider-component> {%- if first_3d_model -%} <button class="button button--full-width product__xr-button" type="button" aria-label="{{ 'products.product.xr_button_label' | t }}" data-shopify-xr data-shopify-model3d-id="{{ first_3d_model.id }}" data-shopify-title="{{ product.title | escape }}" data-shopify-xr-hidden > {% render 'icon-3d-model' %} {{ 'products.product.xr_button' | t }} </button> {%- endif -%} {%- liquid assign is_not_limited_to_single_item = false if limit == null or limit > 1 assign is_not_limited_to_single_item = true endif -%} {%- if is_not_limited_to_single_item and media_count > 1 and section.settings.gallery_layout contains 'thumbnail' or section.settings.mobile_thumbnails == 'show' -%} <slider-component id="GalleryThumbnails-{{ section.id }}" class="thumbnail-slider slider-mobile-gutter quick-add-hidden{% unless section.settings.gallery_layout contains 'thumbnail' %} medium-hide large-up-hide{% endunless %}{% if section.settings.mobile_thumbnails != 'show' %} small-hide{% endif %}{% if media_count <= 3 %} thumbnail-slider--no-slide{% endif %}" > <button type="button" class="slider-button slider-button--prev{% if media_count <= 3 %} small-hide{% endif %}{% if media_count <= 4 %} medium-hide large-up-hide{% endif %}" name="previous" aria-label="{{ 'general.slider.previous_slide' | t }}" aria-controls="GalleryThumbnails-{{ section.id }}" data-step="3" > {% render 'icon-caret' %} </button> <ul id="Slider-Thumbnails-{{ section.id }}" class="thumbnail-list list-unstyled slider slider--mobile{% if section.settings.gallery_layout == 'thumbnail_slider' %} slider--tablet-up{% endif %}" > {%- capture sizes -%} (min-width: {{ settings.page_width }}px) calc(({{ settings.page_width | minus: 100 | times: media_width | round }} - 4rem) / 4), (min-width: 990px) calc(({{ media_width | times: 100 }}vw - 4rem) / 4), (min-width: 750px) calc((100vw - 15rem) / 8), calc((100vw - 8rem) / 3) {%- endcapture -%} {%- if featured_media != null -%} {%- liquid capture media_index if featured_media.media_type == 'model' increment model_index elsif featured_media.media_type == 'video' or featured_media.media_type == 'external_video' increment video_index elsif featured_media.media_type == 'image' increment image_index endif endcapture assign media_index = media_index | plus: 1 -%} <li id="Slide-Thumbnails-{{ section.id }}-0" class="thumbnail-list__item slider__slide{% if section.settings.hide_variants and variant_images contains featured_media.src %} thumbnail-list_item--variant{% endif %}" data-target="{{ section.id }}-{{ featured_media.id }}" data-media-position="{{ media_index }}" data-alt="{{ media.alt }}" > {%- capture thumbnail_id -%} Thumbnail-{{ section.id }}-0 {%- endcapture -%} <button class="thumbnail global-media-settings global-media-settings--no-shadow" aria-label="{%- if featured_media.media_type == 'image' -%}{{ 'products.product.media.load_image' | t: index: media_index }}{%- elsif featured_media.media_type == 'model' -%}{{ 'products.product.media.load_model' | t: index: media_index }}{%- elsif featured_media.media_type == 'video' or featured_media.media_type == 'external_video' -%}{{ 'products.product.media.load_video' | t: index: media_index }}{%- endif -%}" aria-current="true" aria-controls="GalleryViewer-{{ section.id }}" aria-describedby="{{ thumbnail_id }}" > {{ featured_media.preview_image | image_url: width: 416 | image_tag: loading: 'lazy', sizes: sizes, widths: '54, 74, 104, 162, 208, 324, 416', id: thumbnail_id, alt: featured_media.alt | escape }} </button> </li> {%- endif -%} {%- for media in product.media -%} {%- unless media.id == product.selected_or_first_available_variant.featured_media.id -%} {%- liquid capture media_index if media.media_type == 'model' increment model_index elsif media.media_type == 'video' or media.media_type == 'external_video' increment video_index elsif media.media_type == 'image' increment image_index endif endcapture assign media_index = media_index | plus: 1 -%} <li id="Slide-Thumbnails-{{ section.id }}-{{ forloop.index }}" class="thumbnail-list__item slider__slide{% if section.settings.hide_variants and variant_images contains media.src %} thumbnail-list_item--variant{% endif %}" data-target="{{ section.id }}-{{ media.id }}" data-media-position="{{ media_index }}" data-alt="{{ media.alt }}" data-enable-group-media="{{ section.settings.enable_group_media }}" > {%- if media.media_type == 'model' -%} <span class="thumbnail__badge" aria-hidden="true"> {%- render 'icon-3d-model' -%} </span> {%- elsif media.media_type == 'video' or media.media_type == 'external_video' -%} <span class="thumbnail__badge" aria-hidden="true"> {%- render 'icon-play' -%} </span> {%- endif -%} {%- capture thumbnail_id -%} Thumbnail-{{ section.id }}-{{ forloop.index }} {%- endcapture -%} <button class="thumbnail global-media-settings global-media-settings--no-shadow" aria-label="{%- if media.media_type == 'image' -%}{{ 'products.product.media.load_image' | t: index: media_index }}{%- elsif media.media_type == 'model' -%}{{ 'products.product.media.load_model' | t: index: media_index }}{%- elsif media.media_type == 'video' or media.media_type == 'external_video' -%}{{ 'products.product.media.load_video' | t: index: media_index }}{%- endif -%}" {% if media == product.selected_or_first_available_variant.featured_media or product.selected_or_first_available_variant.featured_media == null and forloop.index == 1 %} aria-current="true" {% endif %} aria-controls="GalleryViewer-{{ section.id }}" aria-describedby="{{ thumbnail_id }}" > {{ media.preview_image | image_url: width: 416 | image_tag: loading: 'lazy', sizes: sizes, widths: '54, 74, 104, 162, 208, 324, 416', id: thumbnail_id, alt: media.alt | escape }} </button> </li> {%- endunless -%} {%- endfor -%} </ul> <button type="button" class="slider-button slider-button--next{% if media_count <= 3 %} small-hide{% endif %}{% if media_count <= 4 %} medium-hide large-up-hide{% endif %}" name="next" aria-label="{{ 'general.slider.next_slide' | t }}" aria-controls="GalleryThumbnails-{{ section.id }}" data-step="3" > {% render 'icon-caret' %} </button> </slider-component> {%- endif -%} </media-gallery>
Edit
snippets/product-media-modal.liquid
: Open this file and replace the code with below code.{% comment %} Renders a product media modal. Also see 'product-media-gallery' Accepts: - product: {Object} Product liquid object - variant_images: {Array} Product images associated with a variant Usage: {% render 'product-media-modal' %} {% endcomment %} <product-modal id="ProductModal-{{ section.id }}" class="product-media-modal media-modal"> <div class="product-media-modal__dialog color-{{ section.settings.color_scheme }} gradient" role="dialog" aria-label="{{ 'products.modal.label' | t }}" aria-modal="true" tabindex="-1" > <button id="ModalClose-{{ section.id }}" type="button" class="product-media-modal__toggle" aria-label="{{ 'accessibility.close' | t }}" > {{ 'icon-close.svg' | inline_asset_content }} </button> <div class="product-media-modal__content color-{{ section.settings.color_scheme }} gradient" role="document" aria-label="{{ 'products.modal.label' | t }}" tabindex="0" > {%- liquid if product.selected_or_first_available_variant.featured_media != null assign media = product.selected_or_first_available_variant.featured_media render 'product-media', media: media, loop: section.settings.enable_video_looping, variant_image: section.settings.hide_variants endif -%} {%- for media in product.media -%} {%- liquid if section.settings.hide_variants and variant_images contains media.src or variant_images contains media.id assign variant_image = true else assign variant_image = false endif unless media.id == product.selected_or_first_available_variant.featured_media.id render 'product-media', media: media, loop: section.settings.enable_video_looping, variant_image: variant_image endunless -%} {%- endfor -%} </div> </div> </product-modal>
Edit
snippets/product-variant-picker.liquid
: Open this file and replace the code with below code.{% comment %} Renders product variant-picker Accepts: - product: {Object} product object. - block: {Object} passing the block information. - product_form_id: {String} Id of the product form to which the variant picker is associated. Usage: {% render 'product-variant-picker', product: product, block: block, product_form_id: product_form_id %} {% endcomment %} {%- unless product.has_only_default_variant -%} <variant-selects id="variant-selects-{{ section.id }}" data-section="{{ section.id }}" {{ block.shopify_attributes }} > {%- for option in product.options_with_values -%} {%- liquid assign swatch_count = option.values | map: 'swatch' | compact | size assign picker_type = block.settings.picker_type if swatch_count > 0 and block.settings.swatch_shape != 'none' if block.settings.picker_type == 'dropdown' assign picker_type = 'swatch_dropdown' else assign picker_type = 'swatch' endif endif -%} {%- if picker_type == 'swatch' -%} <fieldset class="js product-form__input product-form__input--swatch" data-option-name="{{ option.name }}"> <legend class="form__label"> {{ option.name }}: <span data-selected-value> {{- option.selected_value -}} </span> </legend> {% render 'product-variant-options', product: product, option: option, block: block, picker_type: picker_type %} </fieldset> {%- elsif picker_type == 'button' -%} <fieldset class="js product-form__input product-form__input--pill" data-option-name="{{ option.name }}"> <legend class="form__label">{{ option.name }}</legend> {% render 'product-variant-options', product: product, option: option, block: block, picker_type: picker_type %} </fieldset> {%- else -%} <div class="product-form__input product-form__input--dropdown"> <label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}"> {{ option.name }} </label> <div class="select"> {%- if picker_type == 'swatch_dropdown' -%} <span data-selected-value class="dropdown-swatch" > {% render 'swatch', swatch: option.selected_value.swatch, shape: block.settings.swatch_shape %} </span> {%- endif -%} <select id="Option-{{ section.id }}-{{ forloop.index0 }}" class="select__select" name="options[{{ option.name | escape }}]" form="{{ product_form_id }}" data-option-name="{{ option.name }}" > {% render 'product-variant-options', product: product, option: option, block: block, picker_type: picker_type %} </select> <span class="svg-wrapper"> {{- 'icon-caret.svg' | inline_asset_content -}} </span> </div> </div> {%- endif -%} {%- endfor -%} <script type="application/json" data-selected-variant> {{ product.selected_or_first_available_variant | json }} </script> </variant-selects> {%- endunless -%}
Update
assets/product-info.js
: In this file, add a new function calledsetVariantImages
. Update the file Update the file with reference to the screenshots below.Update line 17 :
this.setVariantImages()
Update line 308 and 315:
this.setVariantImages()
setVariantImages() { // set variant images in the media gallery const galleryImages = Array.from(document.querySelectorAll('[data-alt]')); const variantOptionNames = Array.from(document.querySelectorAll('[data-option-name]')); let setVariantImages = false; let value; variantOptionNames.forEach((variantOption)=> { if(variantOption.getAttribute('data-option-name').toLowerCase() == 'color') { var inputs = variantOption.querySelectorAll('input'); if (inputs.length) { value = Array.from(variantOption.querySelectorAll('input')).find((radio) => radio.checked).value; } else { value = variantOption.value; } setVariantImages = true; } }) if(setVariantImages) { galleryImages.forEach((galleryImage) => { if((galleryImage.getAttribute('data-alt') == value || galleryImage.getAttribute('data-alt').toLowerCase() == 'public' ) && galleryImage.getAttribute('data-enable-group-media') == 'true') { galleryImage.classList.remove("thumbnail-list_item--variant"); } else { galleryImage.classList.add("thumbnail-list_item--variant"); } }) } }
Set Up Variant Image Alt Text: In your Shopify admin, ensure that each variant image has alt text that exactly matches its corresponding variant option name. Also, make sure that the the variant name is 'color'. If you have images that need to be used for all variants, please set the alt text as 'public'.
By following these steps, you can effectively display only the images of the selected variant in your product gallery. This enhancement will not only improve user experience but also elevate the overall visual appeal of your Shopify store.
For any questions or further assistance, please don't hesitate to reach out. Simply leave us a message, and we will respond to you as soon as possible. We're here to help and look forward to working with you!