How To Show Selected Variant Images [Horizon Theme Shopify]

Add following code in product-information.liquid on top of the file:

{% if product.metafields.custom.selected_variant == true or product.metafields.custom.selected_variant == null %}
<style>
  .hidden {
    display: none !important;
    opacity: 0;
  }
  [data-media-id], .media-item, .thumbnail, .product-media-container, .slideshow-slide, .media-gallery__grid li, .slideshow-controls__dots li {
    opacity: 1;
  }
  /* Hide all slides, dots, and thumbnails until initialized */
  .slideshow-slide, .slideshow-controls__dots li, .thumbnail, .dialog-thumbnails-list__thumbnail {
    display: none;
  }
  .media-gallery[data-variant-images-initialized="true"] .slideshow-slide,
  .media-gallery[data-variant-images-initialized="true"] .slideshow-controls__dots li,
  .media-gallery[data-variant-images-initialized="true"] .thumbnail,
  .media-gallery[data-variant-images-initialized="true"] .dialog-thumbnails-list__thumbnail {
    display: block;
  }
</style>
<script>
(function() {
  let productDataCache = null;
  let lastSelectedColor = null;

  function updateVariantImages(selectedColor, mediaItems, thumbnailButtons, sliders, gridItems, dotItems, mediaGallery) {
    const normalizedSelectedColor = selectedColor ? selectedColor.toLowerCase().replace(/\s+/g, '') : null;
    let foundMatchingImages = false;

    // Hide all images, thumbnails, grid items, and pagination dots
    mediaItems.forEach(mediaItem => {
      mediaItem.classList.add('hidden');
      const parentSlide = mediaItem.closest('slideshow-slide');
      if (parentSlide) parentSlide.classList.add('hidden');
    });
    thumbnailButtons.forEach(button => button.classList.add('hidden'));
    gridItems.forEach(gridItem => gridItem.classList.add('hidden'));
    dotItems.forEach(dot => dot.classList.add('hidden'));

    if (normalizedSelectedColor) {
      // Show only images, thumbnails, grid items, and dots matching the selected color
      mediaItems.forEach((mediaItem, index) => {
        const img = mediaItem.tagName === 'IMG' ? mediaItem : mediaItem.querySelector('img');
        if (img?.alt) {
          const altText = img.alt.toLowerCase().replace(/\s+/g, '');
          if (altText.includes(normalizedSelectedColor)) {
            mediaItem.classList.remove('hidden');
            const parentSlide = mediaItem.closest('slideshow-slide');
            if (parentSlide) {
              parentSlide.classList.remove('hidden');
              parentSlide.style.display = 'block'; // Ensure display is set
            }
            if (dotItems[index]) {
              dotItems[index].classList.remove('hidden');
              dotItems[index].style.display = 'block'; // Ensure display is set
              // Update aria-label to reflect correct slide count
              const visibleDots = dotItems.filter(dot => !dot.classList.contains('hidden')).length;
              dotItems[index].querySelector('button').setAttribute('aria-label', `Slide ${index + 1} of ${visibleDots}`);
            }
            foundMatchingImages = true;
          }
        }
      });
      thumbnailButtons.forEach(button => {
        const img = button.querySelector('img');
        if (img?.alt) {
          const altText = img.alt.toLowerCase().replace(/\s+/g, '');
          if (altText.includes(normalizedSelectedColor)) {
            button.classList.remove('hidden');
            button.style.display = 'block'; // Ensure display is set
          }
        }
      });
      gridItems.forEach(gridItem => {
        const img = gridItem.querySelector('img');
        if (img?.alt) {
          const altText = img.alt.toLowerCase().replace(/\s+/g, '');
          if (altText.includes(normalizedSelectedColor)) {
            gridItem.classList.remove('hidden');
          }
        }
      });
    }

    // Fallback: Show all if no matching images found or no color selected
    if (!normalizedSelectedColor || !foundMatchingImages || !productDataCache?.variants?.length > 1) {
      if (normalizedSelectedColor && !foundMatchingImages) {
        console.log(`Selected Variant Image: No images found for "${selectedColor}". Showing all images.`);
      }
      mediaItems.forEach((mediaItem, index) => {
        mediaItem.classList.remove('hidden');
        const parentSlide = mediaItem.closest('slideshow-slide');
        if (parentSlide) {
          parentSlide.classList.remove('hidden');
          parentSlide.style.display = 'block'; // Ensure display is set
        }
        if (dotItems[index]) {
          dotItems[index].classList.remove('hidden');
          dotItems[index].style.display = 'block'; // Ensure display is set
          // Update aria-label for all dots
          const visibleDots = dotItems.length;
          dotItems[index].querySelector('button').setAttribute('aria-label', `Slide ${index + 1} of ${visibleDots}`);
        }
      });
      thumbnailButtons.forEach(button => {
        button.classList.remove('hidden');
        button.style.display = 'block'; // Ensure display is set
      });
      gridItems.forEach(gridItem => gridItem.classList.remove('hidden'));
    }

    // Refresh sliders/galleries
    sliders.forEach(slider => {
      if (typeof slider.update === 'function') slider.update();
      else if (typeof slider.initPages === 'function') slider.initPages();
      else if (typeof slider.reset === 'function') slider.reset();
      else if (typeof window.Swiper !== 'undefined' && slider.swiper) {
        slider.swiper.update();
        slider.swiper.slideTo(0); // Reset to first slide
      } else {
        window.dispatchEvent(new Event('resize'));
      }
    });

    // Mark gallery as initialized to apply CSS display rules
    if (mediaGallery) {
      mediaGallery.setAttribute('data-variant-images-initialized', 'true');
    }
  }

  function initVariantImages() {
    const mediaGallery = document.querySelector('[data-product-media-gallery], media-gallery, .product__media, .product-media, .media-container, [data-product-media]');
    const productSection = document.querySelector('[data-product-id], .product-variant-id, .product-form, .product__form, [data-product-form], .product__info-container');
    
    if (!mediaGallery || !productSection) {
      console.error('Selected Variant Image: Required elements not found. Media Gallery:', !!mediaGallery, 'Product Section:', !!productSection);
      return;
    }

    const mediaItems = Array.from(mediaGallery.querySelectorAll('img, [data-media-id], .media-item, .product-media-item, slideshow-slide img, .product__media img'));
    const thumbnailButtons = Array.from(mediaGallery.querySelectorAll('.slideshow-controls__thumbnails button, .thumbnail, [data-thumbnail], .dialog-thumbnails-list__thumbnail'));
    const sliders = Array.from(mediaGallery.querySelectorAll('[data-slider], slider-component, .slider, .swiper, .carousel, .product-media-slider'));
    const gridItems = Array.from(mediaGallery.querySelectorAll('.media-gallery__grid li'));
    const dotItems = Array.from(mediaGallery.querySelectorAll('.slideshow-controls__dots li'));

    const showVariantImage = () => {
      if (!productDataCache) {
        console.warn('Selected Variant Image: Product data not yet loaded.');
        return;
      }

      let selectedColor = null;
      const hasMultipleVariants = productDataCache.variants && productDataCache.variants.length > 1;
      const variantSelects = document.querySelector('[data-variant-selects], variant-selects, .variant-picker, .product-form__variants, .product__variants, [data-product-variants], .product__variant-options');

      if (variantSelects && hasMultipleVariants) {
        const currentValues = Array.from(
          variantSelects.querySelectorAll('select option[selected], input:checked, [data-variant-option][aria-selected="true"], [data-variant-option].is-selected, [data-variant-option][class*="selected"]')
        ).map(el => el.value || el.getAttribute('data-variant-option') || el.textContent.trim());

        selectedColor = currentValues.find(value =>
          productDataCache.options.some(opt => opt.values.includes(value))
        );

        if (!selectedColor) {
          console.warn('Selected Variant Image: No matching option value found for current selection:', currentValues);
        }
      }

      if (selectedColor === lastSelectedColor) {
        return; // No change in relevant selection
      }

      lastSelectedColor = selectedColor;
      updateVariantImages(selectedColor, mediaItems, thumbnailButtons, sliders, gridItems, dotItems, mediaGallery);
    };

    if (productDataCache) {
      showVariantImage(); // Initial call if data is already there
    } else {
      const shopifyRoot = window.Shopify?.routes?.root || '/';
      const handle = `products/${"{{ product.handle }}"}.js`;
      fetch(`${shopifyRoot}${handle}`)
        .then(response => {
          if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
          return response.json();
        })
        .then(product => {
          productDataCache = product;
          showVariantImage(); // Call after data is fetched
          // Add event listeners after data is available
          productSection.removeEventListener('change', showVariantImage);
          productSection.removeEventListener('variant:change', showVariantImage);
          productSection.removeEventListener('shopify:variant:change', showVariantImage);
          productSection.removeEventListener('product:variant-updated', showVariantImage);
          productSection.addEventListener('change', showVariantImage);
          productSection.addEventListener('variant:change', showVariantImage);
          productSection.addEventListener('shopify:variant:change', showVariantImage);
          productSection.addEventListener('product:variant-updated', showVariantImage);
        })
        .catch(error => console.error("Selected Variant Image: Error fetching product data:", error));
    }
  }

  if (document.readyState === 'complete' || document.readyState === 'interactive') {
    initVariantImages();
  } else {
    document.addEventListener('DOMContentLoaded', initVariantImages);
  }

  // Mutation observer for dynamic content
  const observerTarget = document.querySelector('[data-product-id]') || document.body;
  const observer = new MutationObserver((mutationsList) => {
    for (const mutation of mutationsList) {
      if (mutation.type === 'childList') {
        const mediaGallery = document.querySelector('[data-product-media-gallery], media-gallery, .product__media, .product-media, .media-container, [data-product-media]');
        if (mediaGallery && !mediaGallery.hasAttribute('data-variant-images-initialized')) {
          mediaGallery.setAttribute('data-variant-images-initialized', 'true');
          initVariantImages();
          break;
        }
      }
    }
  });
  observer.observe(observerTarget, { childList: true, subtree: true });
})();
</script>
{% endif %}
5/5 - (5 votes)

About

Leave a Comment

Your email address will not be published. Required fields are marked *