Unique Hover Effect For Oxygen Builder Repeaters

By James LePage
 on April 7, 2022

Unique Hover Effect For Oxygen Builder Repeaters

By James LePage
 on April 7, 2022

In this tutorial, we're going to build a unique hover effect for content displayed in Oxygen Builder Repeaters. Modeled off of the Codrops "Distortion Hover Effect", and using the source code from that resource, this effect will create a distorted fade to a user-defined image when a visitor hovers on a repeater cell.

This tutorial will incorporate some cool concepts of Oxygen Builder:

  • Advanced repeater techniques
  • ACF field groups and manual integration with Oxygen Builder
  • Basic CSS grid
  • Dynamic attributes
  • Code block usage & intermediate JS

Taking it a step further, we're going to make this a 100% dynamic feature, meaning that it'll be set and forget. No need to initialize a specific effect for each cell!

Follow Along (Source Download):

Note: this is a proof-of-concept, and likely requires optimization for use in production sites.

Two other things:

Effect Demo:


Step 1: ACF Fields

We will use ACF to make this 100% dynamic, and easy for the end user to edit. Make a field group, and add a hover image and displacement image. The initial image will be the featured image of the post. The hover image is what the effect will fade to when the visitor hovers over a repeater post.

The displacement image is what will be used to make the unique morph/fade animation between the two images. In this example, we are using the following images for displacement:

You can actually use any image, but black and white images with great texture are typically the best. It's easy to experiment with this method!

Create field group and assign to the post type.
Each image return format should be the Image URL.

Here's what the field group and associated images look like when adding a new post:

It's easy to swap out any of the three images.

Step 2: Create the structure for the effect

At its core, we are copying the source code from the Codrops example, with minor modifications.

<div class="grid"> <!-- this is the repeater --> <div class="grid__item grid__item--bg"> <!-- this is the div in the repeater --> <div class="grid__item-img" data-displacement="img/displacement/8.jpg" data-intensity="-0.65" data-speedIn="1.2" data-speedOut="1.2"> <!-- this is the "image wrapper div" --> <img src="img/Img22.jpg" alt="Image"/> <img src="img/Img21.jpg" alt="Image"/> </div> <div class="grid__item-content"> <!-- this is the "content wrapper div> --> <span class="grid__item-meta">California</span> <h2 class="grid__item-title">Jumping Around</h2> <h3 class="grid__item-subtitle"> <span>California's last empty jump spots</span> <a class="grid__item-link" href="#">Discover more</a> </h3> </div> </div> </div>

We simply duplicate the HTML structure above, with Oxygen Builder elements. Don't forget to add the classes from the HTML example above, as we're going to add some CSS and the JS uses them to identify specific elements. If you change these classes, you'll need to update the CSS and JS accordingly.

Our Repeater is using CSS grid to evenly space all cells without much work:


Step 3: Make Dynamic

There are several things to configure to be dynamic. First, make the repeater query the WordPress Post type.

Next, set the date and post title to be dynamic.


Now, we will set up the three images. This is where things may get complex. Set the URL of image 1 to be the featured image URL.


Set the URL of image 2 to be the hover image, set in the ACF. For this tutorial, ACF fields weren't showing in the "insert dynamic data" popup (likely due to a bug Oxygen Builder 4.0 Beta 2). There's an easy workaround if you ever experience this:

1 - Insert the dynamic data

2 - Select PHP Function Return Value


3 - manually insert the ACF field content with get_field('fieldname')


Finally, we need to set the distortion image that the effect will use to make the morph transition. This is inserted into the HTML as a data-attribute, which the JS reads and incorporates in the effect. From the HTML above, we can see that there are several attributes, which may be edited to change the effect.

<div class="grid__item-img" data-displacement="img/displacement/8.jpg" data-intensity="-0.65" data-speedIn="1.2" data-speedOut="1.2"> <!-- this is the "image wrapper div" --> ... </div>

The main thing we need to make dynamic is the data-displacement, which will have the URL of the image set in the post using ACF. We hard coded the other three attributes, but you can use the same method outlined below to make these user editable too.

Go to the image wrapper element (the div around the two dynamic images). Click Advanced -> Attributes, and add the following.


For data-displacement, we will make this dynamic by clicking the data+ button in the content, and inserting our corresponding ACF field.

The frontend HTML will look like this, and the JS will use all of this data (which is dynamic and user-editable via ACF) to create the cool displacement hover effect on WordPress:


Step 4: Add CSS, libraries & JS

We will add the following CSS to our Universal CSS stylesheet. You may need to play with additional CSS styles to get everything working well.

.grid__item { overflow:hidden; position:relative; } .grid__item-content { z-index:5; } .grid__item-img { display: block; height: 100%; width: 100%; } .grid__item-img canvas { height: 100%; position:absolute; top:0; z-index:1; } .grid__item-img img { height: 100%; display: block; } /* This is a fallback if the JS dosn't work */ .grid__item-img img:nth-child(2) { position: absolute; top: 0; left: 0; opacity: 0; transition: opacity 0.3s; } .grid__item:hover .grid__item-img img:nth-child(2) { opacity: 1; } .js .grid__item-img img { display: none; }

Finally, we will load the necessary JS libraries, and code (we did this with a code block):

<script src=""></script> <script src=""></script> <script src=""></script> <script src=""></script> <script> imagesLoaded( document.querySelectorAll('img'), () => { document.body.classList.remove('loading'); }); Array.from(document.querySelectorAll('.grid__item-img')).forEach((el) => { const imgs = Array.from(el.querySelectorAll('img')); new hoverEffect({ parent: el, intensity: el.dataset.intensity || undefined, speedIn: el.dataset.speedin || undefined, speedOut: el.dataset.speedout || undefined, easing: el.dataset.easing || undefined, hover: el.dataset.hover || undefined, image1: imgs[0].getAttribute('src'), image2: imgs[1].getAttribute('src'), displacementImage: el.dataset.displacement }); }); </script>

We are using Statically for our example (pulling in the ImagesLoaded and Hover Effect libraries from GitHub), but you should ideally host this on your site, using a tool like Scripts Organizer or Advanced Scripts.

We also load Three.JS and TweenMax.JS, which are the two underlying libraries that work to generate the displacement effect.

Finally, the JS does the following - it identifies when images are loaded and applies the hover effect to any element that has the .grid__item-img, pulling the associated images and displacement images from each post. Completely dynamic and will work regardless of the number of posts returned by the Oxygen Builder repeater.

After adding all of this, your effect should be working!

This was requested by a member of our Isotropic Facebook Group. We invite you to join here.

Subscribe & Share
If you liked this content, subscribe for our monthly roundup of WordPress news, website inspiration, exclusive deals and interesting articles.
Unsubscribe at any time. We do not spam and will never sell or share your email.
Notify of
Inline Feedbacks
View all comments
Article By
James LePage
James LePage is the founder of Isotropic, a WordPress education company and digital agency. He is also the founder of, a venture backed startup bringing AI to WordPress creators.
We're looking for new authors. Explore Isotropic Jobs.
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram