-
-
Save jrevillini/e2fe088455e4007e43a23b3364720690 to your computer and use it in GitHub Desktop.
<?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(); | |
} |
Here's an additional challenge for you.. Seems a flip box background image works differently. ;-)
@slamdive Not sure what flip-box is ... do yo mean you added a motion effect to either a row or column? Or is it an element which serves images using some animation? If that's the case, I can't lazy load them because it would kill the motion effect. In order for motion effects to work, the element with the background needs to be moved from a hidden state/location to a visible one. Since the element with the background is hidden until it's brought into the viewport by Elementor's scripts, my script would have a hard time detecting the right time to load the image. And if it started loading as soon as their script animated it into the viewport, it would probably ruin the animation.
But do let me know if you have any ideas about triggering the image to load. If I can make it work, I will!
hey! The plugin seems to work fine. How do you see how to integrate it with the elementor slide backgrounds? Elementor has now released the swiper APi, maybe you can build something out there so it doesn't load the swiper before it is seen in the viewport. What do you think?
@sermalefico Is it part of regular Elementor or Pro? I'll try to create a test environment and add the capability to lazy load it. Do we know for certain that swiper is not lazy loading for sure? Tell me what I need to create a test environment - like specifically which plugins. Thanks!
Heya!
Flip Box is an Elementor Pro widget.
The main issue is the background image on the front of the Flip Box - the one in view until you hover.
Background image is loaded under the class: .elementor-flip-box__front
hey! The plugin seems to work fine. How do you see how to integrate it with the elementor slide backgrounds? Elementor has now released the swiper APi, maybe you can build something out there so it doesn't load the swiper before it is seen in the viewport. What do you think?
@sermalefico Is it part of regular Elementor or Pro? I'll try to create a test environment and add the capability to lazy load it. Do we know for certain that swiper is not lazy loading for sure? Tell me what I need to create a test environment - like specifically which plugins. Thanks!
This is the elementor anuncament https://developers.elementor.com/expose-swiper-in-elementor/
The slider image background of sections and columns use swiper slider. Whith this new implementation you can interact whith the swiper slider instance of any section. I think it could be a beginning.
I suppose you could make a rule that adds a class to swiper and another to the section that has the background slider feature doesn't start until it's in viewport. If so, Swiper slider has an option in the api to make it lazy.
Heya!
Flip Box is an Elementor Pro widget.
The main issue is the background image on the front of the Flip Box - the one in view until you hover.
Background image is loaded under the class: .elementor-flip-box__front
@slamdive can you shoot me a zip of elementor pro? james at vandertech dot com
I should be able to add support for it.
hey! The plugin seems to work fine. How do you see how to integrate it with the elementor slide backgrounds? Elementor has now released the swiper APi, maybe you can build something out there so it doesn't load the swiper before it is seen in the viewport. What do you think?
@sermalefico Is it part of regular Elementor or Pro? I'll try to create a test environment and add the capability to lazy load it. Do we know for certain that swiper is not lazy loading for sure? Tell me what I need to create a test environment - like specifically which plugins. Thanks!
This is the elementor anuncament https://developers.elementor.com/expose-swiper-in-elementor/
The slider image background of sections and columns use swiper slider. Whith this new implementation you can interact whith the swiper slider instance of any section. I think it could be a beginning.
I suppose you could make a rule that adds a class to swiper and another to the section that has the background slider feature doesn't start until it's in viewport. If so, Swiper slider has an option in the api to make it lazy.
@sermalefico cool. looks like it's part of core so i'll work on this.
hey! The plugin seems to work fine. How do you see how to integrate it with the elementor slide backgrounds? Elementor has now released the swiper APi, maybe you can build something out there so it doesn't load the swiper before it is seen in the viewport. What do you think?
@sermalefico Is it part of regular Elementor or Pro? I'll try to create a test environment and add the capability to lazy load it. Do we know for certain that swiper is not lazy loading for sure? Tell me what I need to create a test environment - like specifically which plugins. Thanks!
This is the elementor anuncament https://developers.elementor.com/expose-swiper-in-elementor/
The slider image background of sections and columns use swiper slider. Whith this new implementation you can interact whith the swiper slider instance of any section. I think it could be a beginning.
I suppose you could make a rule that adds a class to swiper and another to the section that has the background slider feature doesn't start until it's in viewport. If so, Swiper slider has an option in the api to make it lazy.@sermalefico cool. looks like it's part of core so i'll work on this.
This is the options to uddate to swiper
var mySwiper = new Swiper("#swiper", {
preloadImages: false,
lazy: {
loadPrevNext: true,
loadOnTransitionStart: false,
},
});
There is a problem with the lazyload on slider widget. The last slide that is duplicated dont load the background image if is active loop mode.
There is a problem with the lazyload on slider widget. The last slide that is duplicated dont load the background image if is active loop mode.
Confirmed. I am working on it.
There is a problem with the lazyload on slider widget. The last slide that is duplicated dont load the background image if is active loop mode.
Confirmed. I am working on it.
This is so strange! It almost seems like a browser bug. First of all, it wasn't doing this when I released it. I have a test page here https://dev.revillini.com/slider-test/ and I'm pretty sure it was working perfectly a few days ago. Secondly, when I look at the live DOM, the style properties are set correctly on all slides. And thirdly, when the first slide begins to animate out of view, the background image flashes into view. I'm perplexed! Watch this video of how the background image flashes into view for a moment: https://drive.google.com/file/d/13gK_Y5laY_veAModLEUdRIA5BaOOgnF1/view
This is strange indeed!
There is a problem with the lazyload on slider widget. The last slide that is duplicated dont load the background image if is active loop mode.
Confirmed. I am working on it.
This is so strange! It almost seems like a browser bug. First of all, it wasn't doing this when I released it. I have a test page here https://dev.revillini.com/slider-test/ and I'm pretty sure it was working perfectly a few days ago. Secondly, when I look at the live DOM, the style properties are set correctly on all slides. And thirdly, when the first slide begins to animate out of view, the background image flashes into view. I'm perplexed! Watch this video of how the background image flashes into view for a moment: https://drive.google.com/file/d/13gK_Y5laY_veAModLEUdRIA5BaOOgnF1/view
This is strange indeed!
@sermalefico I finally figured it out. It's fixed in version 1.1.2 which is now live on wordpress.org
If you want the explanation, I believe Swiper adds additional DOM elements (copies of slides) after initialization. I had to set a Waypoint check on the swiper container object and, when it came into the viewport, I remove my lazyload class from all slides. This is technically not as efficient as your suggestion to leverage the Swiper API and utilize the native lazy load features, but for some reason I had a hell of a time trying to capture an instance of the Swiper elements and modify the parameters at the right point in time prior to initialization. I hope that Elementor Pro developers add the ability to switch on lazy loading for these right in the Elementor widget options UI.
Let me know how this works for you!
Hey!
I was so happy to find your code and plugin, thank you so much for it! I was excited to try it on my live site's dev version. After activating it nothing changed in loading experience, so I activated it on the live site to be sure about it - and it was the same.
The problem why I need this plugin / code:
If you open https://twentysixbudapest.com/ site, the header image shows up only after the whole page loading, as this is a background image. On some screens the first content below the header image can be visible with a few seconds before the header image - and this have to be solved.
I hope there is an easy way to make the header image load first and not just after the whole page. Can you check it for me, please? Let me know what to do or try, I can manage it on a dev site.
@ZaukaYarria I see that your site is using WP Rocket - have you cleared the WP Rocket Cache? You can do so from the admin bar > WP Rocket > Clear Cache
None of my scripts from the plugin are showing up in the source code of your home page so either the Lazy Load Elementor Background Images plugin is deactivated or the WP Rocket cache are the most likely reason. Make sure you clear the cache AFTER you activate my plugin. Hope this helps! If not, hit me up!
Your plugin is active, so I've cleared the cache in WP Rocket, and now it works. :) Thanks a lot for your help!
This is working on my site, but can I make a feature request?
While it works for background images, it doesn't work on just normal images - if it did then a lot of plugins would be compatible with it. For example on my site here, the images in the accordions don't lazy load because they're not background images.
Thanks for the great plugin though!
@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.
@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.
@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.
@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.
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 !
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?
Is this plugin still supported? I tried to install it, but it didn't work :( I'm using latest Elementor 3.1.3
Not work with the last version of Elementor (3.1.4). :-((
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
}
@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>
@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
@Tygovanommen Thanks, i will test and review result to you
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;
}
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
}
`
hey! The plugin seems to work fine. How do you see how to integrate it with the elementor slide backgrounds? Elementor has now released the swiper APi, maybe you can build something out there so it doesn't load the swiper before it is seen in the viewport. What do you think?