Skip to content

Instantly share code, notes, and snippets.

@jrevillini
Last active June 22, 2022 16:31
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jrevillini/e2fe088455e4007e43a23b3364720690 to your computer and use it in GitHub Desktop.
Save jrevillini/e2fe088455e4007e43a23b3364720690 to your computer and use it in GitHub Desktop.
lazyload elementor background images
<?php
// NEWS!!! NEWS!!! **** FEBRUARY 2020 //
// I rolled this code into a plugin!
// Download plugin Lazy Load Background Images for Elementor. Link is in comments below.
// Or go to https://james.revillini.com/projects/
// if you don't want another plugin, the code below works (last time I checked)
// this code is pretty rough ... I'm happy to take suggestions to rewrite and make it better
// you should be able to add this to functions.php ... personally I use the Code Snippets plugin
// tested with and without caching implemented and cloudflare DNS
// DO NOT USE IN PRODUCTION ENVIRONMENT
// NEW 2020-02-08 ... now lazyloads column backgrounds!!! feedback welcome!!!
// lazyload all background images used in elementor sections AND columns
// add lazy class to all elementor sections and columns
// @TODO figure out why this is not an add_filter situation
add_action( 'elementor/frontend/the_content', function( $content ) {
return preg_replace( ['/(\selementor-section\s)/m', '/(elementor-column-wrap)/m'], ' $1 lazyelementorbackgroundimages ', $content );
} );
// add css to hide bg image on images with lazyelementorbackgroundimages class
// add js (jQuery and Waypoint are dependencies) to remove the lazyelementorbackgroundimages class as the item approaches the viewport
add_action( 'wp_enqueue_scripts', 'lazy_elementor_background_images_js', 999 );
function lazy_elementor_background_images_js () {
if ( is_admin() ) return;
if ( ! ( is_singular() ) ) return;
global $lazy_elementor_background_images_js_added;
ob_start(); ?>
jQuery( function ( $ ) {
if ( ! ( window.Waypoint ) ) {
// if Waypoint is not available, then we MUST remove our class from all elements because otherwise BGs will never show
$('.elementor-section.lazyelementorbackgroundimages,.elementor-column-wrap.lazyelementorbackgroundimages').removeClass('lazyelementorbackgroundimages');
if ( window.console && console.warn ) {
console.warn( 'Waypoint library is not loaded so backgrounds lazy loading is turned OFF' );
}
return;
}
$('.lazyelementorbackgroundimages').each( function () {
var $section = $( this );
new Waypoint({
element: $section.get( 0 ),
handler: function( direction ) {
//console.log( [ 'waypoint hit', $section.get( 0 ), $(window).scrollTop(), $section.offset() ] );
$section.removeClass('lazyelementorbackgroundimages');
},
offset: $(window).height()*1.5 // when item is within 1.5x the viewport size, start loading it
});
} );
});
<?php
$skrip = ob_get_clean();
if ( ! wp_script_is( 'jquery', 'enqueued' ) ) {
wp_enqueue_script( 'jquery' );
}
$lazy_elementor_background_images_js_added = wp_add_inline_script( 'jquery', $skrip );
}
add_action( 'wp_head', 'lazy_elementor_background_images_css' );
function lazy_elementor_background_images_css () {
if ( is_admin() ) return;
if ( ! ( is_singular() ) ) return;
global $lazy_elementor_background_images_js_added;
if ( ! ( $lazy_elementor_background_images_js_added ) ) return; // don't add css if scripts weren't added
ob_start(); ?>
<style>
.lazyelementorbackgroundimages:not(.elementor-motion-effects-element-type-background) {
background-image: none !important; /* lazyload fix for elementor */
}
</style>
<?php
echo ob_get_clean();
}
@jrevillini
Copy link
Author

@Overbord so here's my thinking ... there are many great plugins which already do lazyload for the actual images. There's BJ Lazy Load if you want a free one; and many of the caching plugins such as WP Rocket have it built in. So I have to think about this. It's not a bad idea at all, I would just need to add a bunch of code to try to avoid plugin conflicts.

@Overbord
Copy link

@jrevillini Sure - the thing is that most of those plugins don't actually make lazy loading work with Elementor. WP Rocket's definitely doesn't - I haven't tried BJ Lazy Load but I'll give it a shot.

@jrevillini
Copy link
Author

jrevillini commented Apr 28, 2020

@Overbord I use WP Rocket with Elementor and it definitely works for normal images. Are you sure you turned it on in WP Rocket options? I mean, Elementor just adds a bunch of layout stuff and some widget stuff, but in most image-related cases, it's outputting [img] tags which are all generall handled correctly by lazy loading plugins as long as Elementor doesn't load images in via Javascript AFTER the lazyload plugin has run.

@Overbord
Copy link

@jrevillini Okay I just disabled lazy loading while I messed around with Optimole, then deactivated Optimole, and now lazy-loading's working.

So yeah maybe you're right and it's not necessary.

@skiild
Copy link

skiild commented Aug 9, 2020

Hi, as I really don't understand PHP, would you mind telling me how to add some code to exclude lazyloading on section having a specific class ? (or only include the one with a specific class ?)
Background image that are visible when the page is load are first invisible then loaded, which gives the impression of a slower loading, so I would like to ignore my first background image.
Thanks !

@harendrasingh21
Copy link

harendrasingh21 commented Dec 20, 2020

Hi @jrevillini,

I have tried the above code using code Snippets & Plugin also it did not working any idea? is this support with latest elementor version?

@DeoThemes
Copy link

DeoThemes commented Mar 7, 2021

Is this plugin still supported? I tried to install it, but it didn't work :( I'm using latest Elementor 3.1.3

@momo-fr
Copy link

momo-fr commented Apr 12, 2021

Not work with the last version of Elementor (3.1.4). :-((

@Tygovanommen
Copy link

Tygovanommen commented Feb 23, 2022

I refactored the code and made it work for Elementor (3.5.5) and Elementor PRO (3.6.2)

add_action('elementor/frontend/the_content', 'filter_the_content');
function filter_the_content($content)
{
            return preg_replace(['/elementor-section /', '/elementor-column /'], '$0 lazyelementorbackgroundimages ', $content);
}

add_action('wp_head', 'lazy_load_background_images', 999);
function lazy_load_background_images()
{
    if (is_admin()) return;
            ?>
            <script>
              jQuery(function ($) {
                // Disable lazy-load if Waypoint is not available
                if (!(window.Waypoint)) {
                  $('.elementor-section.lazyelementorbackgroundimages,.elementor-column .lazyelementorbackgroundimages').removeClass('lazyelementorbackgroundimages');
                  return;
                }

                // Lazy load images
                $('.lazyelementorbackgroundimages').each(function () {
                  const section = $(this);
                  new Waypoint({
                    element: section.get(0),
                    handler: function () {
                      section.removeClass('lazyelementorbackgroundimages');
                    },
                    offset: $(window).height() * 1.5
                  });
                });
              });
            </script>
            <style>
                .lazyelementorbackgroundimages, .lazyelementorbackgroundimages .elementor-widget-wrap {
                    background-image: none !important;
                }
            </style>
            <?php
}

@masoudnkh
Copy link

masoudnkh commented Feb 24, 2022

@Tygovanommen can this code work for elementor image gallery?
i have element like this :
<div class="e-gallery-image elementor-gallery-item__image" data-thumbnail="../uploads/2021/11/L01.png" data-width="450" data-height="450" alt="" style="background-image: url("../uploads/2021/11/L01.png");"></div>

@Tygovanommen
Copy link

@masoudnkh adjust function filter_the_content from:
return preg_replace(['/elementor-section /', '/elementor-column /'], '$0 lazyelementorbackgroundimages ', $content);
to
return preg_replace(['/elementor-section /', '/elementor-column /', '/e-gallery-image /'], '$0 lazyelementorbackgroundimages ', $content);
I haven't tested it

@masoudnkh
Copy link

@Tygovanommen Thanks, i will test and review result to you

@peixotorms
Copy link

peixotorms commented Mar 22, 2022

Edit of @Tygovanommen code to exclude the first section and improve web vitals:

function filter_the_content($content){
  $content = preg_replace(['/elementor-section /', '/elementor-column /', '/e-gallery-image /'], '$0 lazyelementorbackgroundimages ', $content);
  $pos = strpos($content, 'lazyelementorbackgroundimages');
  if ($pos !== false) { $content = substr_replace($content, '', $pos, strlen('lazyelementorbackgroundimages')); }
  return $content;
}

@adamhodson
Copy link

Ran into an issue where inline css was broken due to the "lazyelementorbackgroundimages" class being injected into the class definitions. Also included an update so that the first section will be excluded and the waypoint logic will not kick off until there's some sort of user interaction (this is for images that are just below the fold but would still trigger the lazy load to fire).

`
add_action('elementor/frontend/the_content', 'filter_the_content');
function filter_the_content($content)
{
//return $content;
return preg_replace(['/"elementor-section /', '/"elementor-column /', '/"elementor-background-overlay /', '/"elementor-background-overlay/'], '$0 lazyelementorbackgroundimages ', $content);
}

add_action('wp_head', 'lazy_load_background_images', 999);
function lazy_load_background_images()
{
if (is_admin()) return;
?>
<script>
jQuery(function ($) {

            if (!(window.Waypoint)) {
              $('.elementor-section.lazyelementorbackgroundimages,.elementor-column .lazyelementorbackgroundimages').removeClass('lazyelementorbackgroundimages');
              return;
            }

            function fireUserIntScripts(){

                // Lazy load images
                $('.lazyelementorbackgroundimages').each(function () {
                  const section = $(this);
                  new Waypoint({
                    element: section.get(0),
                    handler: function () {
                      section.removeClass('lazyelementorbackgroundimages');
                    },
                    offset: $(window).height() * 1.5
                  });
                });

                document.removeEventListener('mousedown', fireUserIntScripts);
                document.removeEventListener('mousemove', fireUserIntScripts);
                document.removeEventListener('touchstart', fireUserIntScripts);
                document.removeEventListener('scroll', fireUserIntScripts);
                document.removeEventListener('keydown', fireUserIntScripts);    

            }

            


            document.addEventListener('mousedown', fireUserIntScripts);
            document.addEventListener('mousemove', fireUserIntScripts);
            document.addEventListener('touchstart', fireUserIntScripts);
            document.addEventListener('scroll', fireUserIntScripts);
            document.addEventListener('keydown', fireUserIntScripts);



          });
        </script>
        <style>
            .lazyelementorbackgroundimages:not(.elementor-section:first-of-type), .lazyelementorbackgroundimages .elementor-widget-wrap {
                background-image: none !important;
            }
        </style>
        <?php

}
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment