On hover – switch WooCommerce product image to gallery image

With the help of ChatGPT. I began exploring how to switch product image on hover.

I had to share that I was using Full Site Editing, the theme Twenty Twenty Four, the new product editor as well as use dev tools to share code elements for the archive image as well as the single product image. After a lot of testing I accomplished what I needed. I have also tested with the themes: Storefront and the default theme Twenty Twenty One (none FSE theme).

On any archive page, category or shop. Hovering over any image that has gallery images will switch to the first gallery image.

Gullhuset WooCommerce products archive page
Gullhuset WooCommerce products archive page.

The PHP code snippet used for the archive pages.

/**
 * WooCommerce: Add hover effects to product thumbnails
 * - Swap to first gallery image on hover
 * - Smooth transition effect for image swap
 * - Remove title attribute on hover
 */

// Hook to enqueue styles for hover effect
add_action('wp_enqueue_scripts', function () {
    // CSS for hover image swap and smooth transition
    $custom_css = '
        /* Class for product hover effect */
        .product-hover-effect {
            position: relative;
            overflow: hidden;
        }

        /* Class for hover image (second image) */
        .product-hover-effect img.hover-image {
            position: absolute;
            top: 0;
            left: 0;
            opacity: 0;
            transition: opacity 0.5s ease-in-out; /* Smooth transition */
        }

        /* When hovering, show the hover image */
        .product-hover-effect:hover img.hover-image {
            opacity: 1;
        }

        /* Smooth transition for main image */
        .product-hover-effect img {
            transition: transform 0.3s ease-in-out; /* Optional: add zoom effect */
        }
    ';
    wp_add_inline_style('woocommerce-inline', $custom_css);
}, 20);

// Filter to add hover effect and remove title attribute for product category pages and single product pages
add_filter('woocommerce_product_get_image', function ($image, $product, $size, $attr, $placeholder, $image_size) {
    // Check if on product category or single product pages
    if ((is_product() || is_product_category()) && is_a($product, 'WC_Product')) {
        // Get gallery image IDs
        $gallery_image_ids = $product->get_gallery_image_ids();

        if (!empty($gallery_image_ids)) {
            // Store main image as $main_img
            $main_img = $image;

            // Remove title attribute to prevent the tooltip
            if (isset($attr['title'])) {
                unset($attr['title']);
            }

            // Generate the hover image (first gallery image)
            $gallery_img_html = wp_get_attachment_image(
                $gallery_image_ids[0],
                $size,
                false,
                array_merge($attr, ['class' => 'hover-image']) // Add class to the hover image
            );

            // Wrap both images with a container div for hover effect
            return '<div class="product-hover-effect">' . $main_img . $gallery_img_html . '</div>';
        }
    }

    // Return the original image if no gallery images are found
    return $image;
}, 10, 6);

This should work well with Site Editing and a default theme. As well as the new product editor in WooCommerce.

Hover the single product image in WooCommerce.

Hovering over the main product image it would switch to the second gallery image on hover.
Here is the code for that. It disables the default zoom and removes the zoom icon. One can explore the code.

// Disable WooCommerce zoom and lightbox; switch main image on hover to second gallery image with smooth transition
add_action('wp', function () {
    if (is_product()) {
        remove_theme_support('wc-product-gallery-zoom');
        remove_theme_support('wc-product-gallery-lightbox');
    }
}, 99);

add_action('wp_footer', function () {
    if (!is_product()) return;
    ?>
    <style>
        .single-product .woocommerce-product-gallery img.wp-post-image {
            transition: opacity 0.4s ease-in-out;
        }

        .single-product .woocommerce-product-gallery img.wp-post-image.hovering {
            opacity: 0.3;
        }
    </style>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const mainImage = document.querySelector('.woocommerce-product-gallery img.wp-post-image');
            const galleryImages = document.querySelectorAll('.woocommerce-product-gallery__image img');

            if (mainImage && galleryImages.length > 1) {
                const secondImage = galleryImages[1];
                const originalSrc = mainImage.getAttribute('src');
                const originalSrcSet = mainImage.getAttribute('srcset');
                const originalSizes = mainImage.getAttribute('sizes');

                let hoverSrc = secondImage.getAttribute('src');
                const srcset = secondImage.getAttribute('srcset');
                if (srcset) {
                    const srcList = srcset.split(',').map(item => item.trim().split(' ')[0]);
                    if (srcList.length > 0) {
                        hoverSrc = srcList[srcList.length - 1];
                    }
                }

                if (hoverSrc) {
                    mainImage.addEventListener('mouseenter', function () {
                        mainImage.classList.add('hovering');
                        setTimeout(() => {
                            mainImage.setAttribute('src', hoverSrc);
                            mainImage.removeAttribute('srcset');
                            mainImage.removeAttribute('sizes');
                            mainImage.classList.remove('hovering');
                        }, 200); // time to fade out before switching
                    });

                    mainImage.addEventListener('mouseleave', function () {
                        mainImage.classList.add('hovering');
                        setTimeout(() => {
                            mainImage.setAttribute('src', originalSrc);
                            mainImage.setAttribute('srcset', originalSrcSet);
                            mainImage.setAttribute('sizes', originalSizes);
                            mainImage.classList.remove('hovering');
                        }, 200);
                    });
                }
            }
        });
    </script>
    <?php
}, 100);

Thanks to ChatGPT Ai with producing the code snippet I added to the Code Snippet plugin Pro.

I added a support question into the wp.org WooCommerce plugin section here:
https://wordpress.org/support/topic/switching-product-image-to-first-gallery-image-on-hover/#post-18466479
Then answered myself with a link to this tutorial. As I begin using the code I might do some additional explorations.

Share the article:

Leave a Reply

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