How to create a Masonry Image Filter in Divi

by | Aug 25, 2021 | 0 comments

Preview

Hey Guys! One of the most recurring request I see in the Divi groups is “How can we add a simple filter on my Divi website?”. Well, today we’re going to implement that without using any plugin – just by using the default Divi modules and a bit of custom codes. Here is a preview of the final result:

Description

If you guys are like me, you are looking for solutions that will make your life easier. It means that the solution should be easy to implement and doesn’t require much maintenance in the future. The last thing you want is to create the filters manually based on what our client provides today – that may change tomorrow – and keep maintaining a giant bloated JavaScript script based on specific categories.

Instead, what you want is to create a dynamic function that will take care of all the filter attributes so you just have to say “hey Divi, this image belongs to the category X, just include it inside our filter and make it look good! Ok, thanks”. Well, we have you covered on this! Simply import our Freebie into your website and:

  • Upload your own images inside the Image modules and change the class to match your own filter categories. Your can even duplicate the image modules to add unlimited images.
  • Style the Call-to-action module so the filter buttons match your branding styles
  • Update the CSS variables inside the CSS file to style the filter buttons when they are active

And that’s it.

Now if your client asks “hey buddy, can you put this image in the category Y instead of X?”, you just have to change the module class – 7 seconds of work – and it’s fixed. If he wants to add more images to the filter or even create a new category, it’s as easy as duplicating the existing modules and adapt the class to the corresponding category. Lovely isn’t it?

Custom CSS

The CSS is pretty straightforward here. We are using it for:

  • styling our active buttons (using CSS variables).
  • creating space between our images in a responsive way (using media queries for mobiles, tablets and Desktop).
  • hiding our default Filter button on frontend and apply the styles to the visibles filters created by our JavaScript function.

Here is the custom CSS used in this layout. Whenever you need to copy/paste it to your website, you can quickly do it by pressing the button below the code window, and it will copy all the code to your clipboard.

<style>
/*
Template: Masonry Filter Images for Divi
Author: Maxime Beguin
Company: Divi Agency
URL: https://divi.agency/
Version: 1.0.0
Licence: MIT
*/

:root {
   --damfi_active-button-text-color: #ffffff;
   --damfi_active-button-bg-color: #ff8181;
   --damfi_active-button-border-color: #ff8181;
}


/* SET THE CURSOR TO POINTER WHEN HOVERING THE FILTER BUTTONS */

.damfi__section .et_pb_promo_button {
   cursor: pointer;
}


/* SET THE ACTIVE BUTTON STYLE */

body.et-db #page-container #et-boc .et-l .et_pb_section.damfi__section .et_pb_cta_0.et_pb_promo .et_pb_promo_button.et_pb_button.filter-item.is-checked {
   color: var(--damfi_active-button-text-color) !important;
   background-color: var(--damfi_active-button-bg-color) !important;
   border-color: var(--damfi_active-button-border-color) !important;
}


/* POSITIONING - SETTING THE WIDTH AND GLUTTER */


/* --MOBILE */

.damfi__section .filtered__item,
.damfi__section .grid-sizer {
   width: 100%;
   margin-bottom: calc(calc(20px/2) * 2) !important;
}


/* --TABLET */

@media screen and (min-width: 768px) {
   .damfi__section .filtered__item,
   .damfi__section .grid-sizer {
      width: calc(calc(100%/2) - calc(20px/2));
   }
}


/* --DESKTOP */

@media screen and (min-width: 981px) {
   .damfi__section .filtered__item,
   .damfi__section .grid-sizer {
      width: calc(calc(100%/3) - calc(40px/3));
      margin-bottom: calc(calc(40px/3) * 2) !important;
   }
}


/*VISUAL BUILDER ONLY*/


/* --SHOW THE IMAGES AS A GRID ON THE VB */

.et-fb-root-ancestor .et-db #et-boc .et-l .damfi__section .filtered__row .et_pb_column {
   display: grid;
   grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
   grid-gap: 20px;
}

.et-fb-root-ancestor .et-db #et-boc .et-l .damfi__section .filtered__item {
   width: 100%;
}


/* --SHOW DEFAULT BUTTON ON THE THEME EDITOR ONLY */

.et-fb-root-ancestor .et-db #et-boc .et-l .damfi__section .et_pb_promo_button,
.damfi__section .et_pb_promo_button.filter-item {
   display: inline-block !important;
}

.damfi__section .et_pb_promo_button {
   display: none !important;
}

.et-fb-root-ancestor .et-db #et-boc .et-l .visual-builder-onlly__code-module-style {
   display: block;
   color: #fff;
   background: #ef5858;
   border: 1px dashed #ffffff;
   padding: 20px;
   text-align: center;
}

.visual-builder-onlly__code-module-style {
   display: none;
}

</style>

Custom JavaScript

The main idea here is to assign a category to each image and then our JS code will automatically create the button filters and apply the correct filters on click event.

A standard way to apply the filter functionality is to use a data attribute in our HTML structure. Unfortunately, Divi has no options yet to add data attributes to specific modules. So we are going to use a workaround and apply our categories to the class field instead. Once each image module has been assigned to a specific category, our JavaScript function will:

  • automatically pick up the class in each image module, and use it to create our data attributes
  • create a button filter for each category and append them inside the Call-to-action module in order to be able to style them using the Visual builder.
  • activate the filter function using the correct data attributes when each button get clicked. We are going to use an external JS library called Isotope JS to manage both the filter and the animation.
  • Manage the active status when a filter button get clicked.

Here is the custom JavaScript used. Again, if you just want to copy/paste the code, feel free to use your Copy to Clipboard button below the code window.

<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script>
<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>
<script>
/*
Template: Masonry Filter Images for Divi
Author: Maxime Beguin
Company: Divi Agency
URL: https://divi.agency/
Version: 1.0.0
Licence: MIT
*/
  
jQuery(document).ready(function ($) {

   // PREPEND THE GRID-SIZER IN ORDER TO MAKE OUR FILTERED GRID RESPONSIVE
   var $newdiv = $("<div class='grid-sizer'></div>");
   $('.damfi__section .masonry-grid').prepend($newdiv);

   // ADD CLASS TO THE FILTER BUTTONS WRAPPER
   $('.damfi__section .et_pb_button_wrapper').addClass('button-group filters-button-group');

   // ISOTOPE INIT
   var $grid = $('.damfi__section .masonry-grid').isotope({
      itemSelector: '.damfi__section .filtered__item',
      filter: '*',
      masonry: {
         columnWidth: '.grid-sizer',
         gutter: 20
      }
   });

   // AVOID UNLOADED IMAGE TO CREATE ELEMENTS OVERLAP
   $grid.imagesLoaded().progress(function () {
      $grid.isotope('layout');
   });

   // FILTER
   let arrCat = ['All'];
   const cat = $('.damfi__section .filtered__item');

   // CREATE THE ARRAY AND ADD DATA-CATEGORY
   cat.each(function () {
      let ArrcatName = $(this).attr('class').split(' ');
      let catName = ArrcatName[ArrcatName.indexOf(ArrcatName.find(element => element === 'filtered__item')) + 1];
      if (arrCat.indexOf(catName) === -1) arrCat.push(catName);
      $(this).attr('data-category', catName);
   });

   // ADD FILTER ITEMS
   for (var i = 0; i < arrCat.length; i++) {
      let menuItem = "<a class='et_pb_button et_pb_promo_button filter-item' data-filter='." + arrCat[i] + "'>" + arrCat[i].replace('_', ' ') + "</a>";
      $('.damfi__section #filter .et_pb_button_wrapper').append(menuItem);
   };
   $('.damfi__section .button-group a.filter-item').first().attr('data-filter', '*');

   // FILTER THE IMAGES ON CLICK
   $('.damfi__section .filters-button-group').on('click', 'a', function () {
      var filterValue = $(this).attr('data-filter');
      $grid.isotope({
         filter: filterValue
      });
   });

   // SET FILTER BUTTON AS ACTIVE ON CLICK
   $('.damfi__section .button-group').each(function (i, buttonGroup) {
      var $buttonGroup = $(buttonGroup);
      $buttonGroup.on('click', 'a', function () {
         $buttonGroup.find('.is-checked').removeClass('is-checked');
         $(this).addClass('is-checked');
      });
   });

   // SET THE FIRST FILTER BUTTON AS ACTIVE ON LOAD
   $('.damfi__section .button-group a.filter-item').first().addClass('is-checked');
});
</script>

Additional Notes

At the moment, the filter doesn’t support multiple categories assigned to a single Image module. So use this solution if your images belong to a unique category. If we get enough requests in the comments, we might fix that. But we need some sort of encouragement!

We are also aware of a bug where images won’t be positioned correctly inside the grid when using the “lazyload images” function of WP Rocket. We recommend disabling lazyload options on the pages where this filter is running.

Final Thoughts

Well, that’s all folks. It should be quite straightforward now to include a nice, lightweight, and responsive image filter to your Divi website and make your clients amazed at how fast you are able to include such custom functions into Divi.

Let me know what you think about it in the comments below. And if you want to show some love, I’d really appreciate a review on our facebook page.

Maxime Beguin

Maxime Beguin

Founder & CEO of Divi Agency

My journey as a self-taught Full Stack Developer started in 2011. Back in the days, I was mainly building HTML/CSS websites using Notepad++ and Joomla (tears of nostalgy…). I started using WordPress a few years later while I was learning PHP and JavaScript, and decided to completely embrace the Divi Community. I’m now the CEO of Divi Agency – a white label agency based In Bologna (Italy) 100% focused on helping other agencies and freelancers growing their Divi Business – but I still try to dedicate time to help people in the various Divi groups on Facebook and to write free tutorials on this blog.

For agencies

Looking for a White Label partner?

We’re happy to work with other agency owners, from freelancers looking to diversify income, to any companies looking to outsource workflow. We love connecting with like-minded individuals and collaborating to exceed client expectations together.

Suscribe to our Newsletter

0 Comments

Submit a Comment

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

More Freebies

GSAP has been extremely popular in the last years to create awesome animations on both website and mobile apps environments. Now is the perfect time to fully integrate it into your next Divi projects as a good alternative to popups.

GSAP has been extremely popular in the last years to create awesome animations on both website and mobile apps environments. Now is the perfect time to fully integrate it into your next Divi projects as a good alternative to popups.

Adding a subtle animation to your menu can increase the curiosity of your visitors and the overall user experience. This tutorial will show you how to create a fullwidth menu using the trendy circular reveal animation.