In this tutorial, you’ll learn how to add interactivity to your WooCommerce stores by showing a second image on product hover inside loops (e.g. archive pages, related products, etc.). This is a feature that many premium WooCommerce themes provide. But, as you’ll see, it’s not that hard to code by ourselves!
This tutorial expects that you are familiar with WordPress and WooCommerce theme development.
Here’s an introductory video that showcases the expected behavior:
Implementation
As usual, for better demonstration, I’ll set up a custom base theme on a local WordPress/WooCommerce installation. I’ll work with their latest versions at the time of this writing (WP 6.4.1/WC 8.3.1).
In the admin, I’ve created three simple products:
Each product has its own image and potentially one or more additional images—all images come from Unsplash:
For my design, I want the product images to be square, so I’ll upload images 1000×1000 with the following settings—in your case they might differ:
Next, I’ll disable WooCommerce default styles—I always do this as I want to have complete control of the styles:
1 |
//functions.php
|
2 |
|
3 |
add_filter( 'woocommerce_enqueue_styles', '__return_empty_array' ); |
Moving on, although completely of secondary importance, I’ll include my beloved UIkit front-end framework to the theme to speed up the development process.
By doing so, my shop page will look like this:
Secondary Image on Hover
This looks ok, but honestly, it isn’t the goal of this tutorial. What I need is a way to change the product image on hover.
Now, many of you might wonder which image will I show. Well, we have lots of options; I can show the first image from the product gallery, a random one from that gallery, or even another image coming from an image field.
In this example, I’ll go with the first option and reveal the first image from the product gallery. To do so, I’ll override the WooCommerce content-product.php
file.
To be more specific, after the woocommerce_before_shop_loop_item
hook, I’ll add a div
with the class of image-wrapper
which will wrap anything inside the woocommerce_before_shop_loop_item_title
hook.
This code will check if the product image gallery isn’t empty. If that’s the case, it’ll grab the ID of the first image and print its HTML representation using the wp_get_attachment_image()
function. Note that the image size will be the woocommerce_thumbnail
one that applies to the catalog pages, and earlier I set it to 750px. Also, the image will receive the img-back
class for easier targeting through the CSS.
Here’s the required code addition:
1 |
<?php
|
2 |
/**
|
3 |
* yourtheme/woocommerce/content-product.php
|
4 |
*
|
5 |
* code after the woocommerce_before_shop_loop_item hook
|
6 |
*/
|
7 |
?>
|
8 |
|
9 |
<div class="image-wrapper"> |
10 |
<?php
|
11 |
$product_gallery = $product->get_gallery_image_ids(); |
12 |
|
13 |
if ( ! empty( $product_gallery ) ) : |
14 |
echo wp_get_attachment_image( |
15 |
$product_gallery[0], |
16 |
'woocommerce_thumbnail', |
17 |
false, |
18 |
array( |
19 |
'class' => 'img-back', |
20 |
)
|
21 |
);
|
22 |
endif; |
23 |
|
24 |
do_action( 'woocommerce_before_shop_loop_item_title' ); |
25 |
?>
|
26 |
</div>
|
After overriding this WooCommerce template in my theme, my archive pages will look like this:
As you can see, both the main product image (bottom image) and the first product gallery image (top image) appear.
What I miss now is just some styles. Through the CSS, I’ll hide the first image and show it only on hover—depending on your theme, this code might not work without tweaks:
1 |
.woocommerce-LoopProduct-link { |
2 |
display: inline-block; |
3 |
}
|
4 |
|
5 |
.woocommerce-LoopProduct-link .image-wrapper { |
6 |
position: relative; |
7 |
}
|
8 |
|
9 |
.woocommerce-LoopProduct-link .img-back { |
10 |
position: absolute; |
11 |
top: 0; |
12 |
left: 0; |
13 |
width: 100%; |
14 |
display: none; |
15 |
}
|
16 |
|
17 |
/*Optional*/
|
18 |
.woocommerce-LoopProduct-link:hover { |
19 |
text-decoration: none; |
20 |
color: #333; |
21 |
}
|
22 |
|
23 |
.woocommerce-LoopProduct-link:hover .img-back { |
24 |
display: block; |
25 |
}
|
In terms of the output markup, here’s the generated HTML for a product inside the loop:
Another thing to note is that here, all my images have equal dimensions, so I don’t have to use properties like object-fit: cover
and height: 100%
to position the second image.
Overriding WooCommerce Styles
Bear in mind that above, I described a scenario where I removed WooCommerce default styles and started the styling from scratch.
But in case I wanted to keep the default styles, I’d change some of my selectors to match WooCommerce ones and prevent overrides due to greater CSS specificity like this:
1 |
.woocommerce ul.products li.product a .img-back { |
2 |
position: absolute; |
3 |
top: 0; |
4 |
left: 0; |
5 |
width: 100%; |
6 |
display: none; |
7 |
}
|
8 |
|
9 |
.woocommerce ul.products li.product a:hover .img-back { |
10 |
display: block; |
11 |
}
|
Using Hooks
An alternative implementation, instead of adding the extra code inside the content-product.php
file, is to print this code through two custom functions that will run during the woocommerce_before_shop_loop_item_title
hook.
An important aspect is to ensure that these functions will run in the correct order. To make this happen, they should have specific priorities following the priorities of the rest of the functions of this hook.
With this in mind, I’ll place this code in the functions.php
of my theme:
1 |
function playground_start_wrapper_div_print_second_product_img() { |
2 |
global $product; |
3 |
$product_gallery = $product->get_gallery_image_ids(); |
4 |
echo '<div class="image-wrapper">'; |
5 |
|
6 |
if ( ! empty( $product_gallery ) ) : |
7 |
echo wp_get_attachment_image( |
8 |
$product_gallery[0], |
9 |
'woocommerce_thumbnail', |
10 |
false, |
11 |
array( |
12 |
'class' => 'img-back', |
13 |
)
|
14 |
);
|
15 |
endif; |
16 |
}
|
17 |
|
18 |
function playground_close_wrapper_div_print_second_product_img() { |
19 |
echo '</div>'; |
20 |
}
|
21 |
|
22 |
add_action( 'woocommerce_before_shop_loop_item_title', 'playground_start_wrapper_div_print_second_product_img', 9 ); |
23 |
add_action( 'woocommerce_before_shop_loop_item_title', 'playground_close_wrapper_div_print_second_product_img', 11 ); |
The styles will remain the same as well as the end result.
Conclusion
During this tutorial, we dived into the WooCommerce e-commerce platform and discussed two ways to reveal a secondary product image upon hovering on the products within loops.
Hopefully, you’ve found this exercise useful enough, and you’ll give it a shot in your upcoming WooCommerce projects. Just remember that depending on your theme setup, especially if you haven’t built it from scratch, you probably have to modify your code to adopt this functionality.
If you want to see more WooCommerce tips and tricks, do let us know through X!
As always, thanks a lot for reading!