Lazy loading images is an effective technique to improve the performance of your WordPress website. By loading images only when they enter the viewport, you can significantly reduce the initial load time and enhance the user experience. In this article, I’ll demonstrate how to implement lazy loading for images in WordPress using a custom approach.
![](https://youssefbouhlal.com/wp-content/uploads/2024/06/image-lazy-loading.webp)
1. Start the Buffer to Change <img>
Tags
First, initiate an output buffer in the template_redirect
action. However, ensure this does not occur during an AJAX call. Add a callback function to ob_start
, which I will explain in the next section.
function youbou_start_buffer() {
if ( wp_doing_ajax() ) {
return;
}
ob_start( 'youbou_filter_buffer' );
}
add_action( 'template_redirect', 'youbou_start_buffer' );
2. Filter the Content
The callback function for ob_start
will look for all <img>
tags in the page’s HTML. It will replace the src
and srcset
attributes with data-src
and data-srcset
, respectively, preventing images from loading immediately. Additionally, it will add a class to the <img>
tags for easier selection with JavaScript.
function youbou_filter_buffer( $buffer ) {
$img_pattern = '/<img.*?src=\".*?\".*?>/';
if ( preg_match_all( $img_pattern, $buffer, $matches, PREG_PATTERN_ORDER ) ) {
foreach ( $matches[0] as $key => $image ) {
$new_image = $image;
//Change src to data attributes.
$new_image = preg_replace( '/<img(.*?)(src=)(.*?)>/i', '<img$1data-$2$3>', $new_image );
//Change srcset to data attributes.
$new_image = preg_replace( '/<img(.*?)(srcset=)(.*?)>/i', '<img$1data-$2$3>', $new_image );
//Add 'youbou-lazyload' class to each image that already has a class.
$new_image = preg_replace( '/<img(.*?)class=\"(.*?)\"(.*?)>/i', '<img$1class="$2 youbou-lazyload"$3>', $new_image );
//Add 'youbou-lazyload' class to each image that doesn't already have a class.
$new_image = preg_replace( '/<img((.(?!class=))*)\/?>/i', '<img class="youbou-lazyload"$1>', $new_image );
$buffer = str_replace( $image, $new_image, $buffer );
}
}
return $buffer;
}
3. End the Buffer
Using the shutdown
action, ensure that the output buffer is only flushed if it contains content and if the request is not an AJAX call.
function youbou_end_buffer() {
if ( wp_doing_ajax() ) {
return;
}
if ( ob_get_length() ) {
ob_end_flush();
}
}
add_action( 'shutdown', 'youbou_end_buffer', 999 );
4. Load Images with JavaScript
Use JavaScript to select all images with the youbou-lazyload
class and observe them to detect when they enter the viewport. When an image is in the viewport, its data-src
and data-srcset
attributes are moved back to src
and srcset
, respectively. A class is added to the image to handle the opacity transition.
const imageLazyloading = () => {
const images = document.querySelectorAll( 'img.youbou-lazyload' );
const options = {
rootMargin : '200px',
threshold : 0
}
const observer = new IntersectionObserver( ( entries, observer ) => observerCallback( entries, observer ), options );
/**
* observe all the images
*/
images.forEach( image => {
observer.observe( image );
});
/**
* Observer callback
*/
const observerCallback = ( images, observer ) => {
images.forEach( image => {
// return if the image not in the dom yet.
if( ! image.isIntersecting ) return;
// change the data-src to src.
loadImage( image.target );
// remove the image from the observer.
observer.unobserve( image.target );
});
}
/**
* Load an image
*/
const loadImage = image => {
// get the attributes.
let src = image.dataset.src;
let srcSet = image.dataset.srcset;
// set src attributes.
if ( src ) {
image.src = src;
image.removeAttribute('data-src');
}
// set srcset attributes.
if( srcSet ) {
image.srcset = srcSet
image.removeAttribute('data-srcset');
}
// add class for fading.
image.classList.add('youbou-lazyload__loaded');
}
};
document.addEventListener( 'DOMContentLoaded', imageLazyloading );
4. CSS for Fading
To ensure a smooth transition for the images as they load, use CSS to initially hide the images and then gradually make them visible.
img.youbou-lazyload {
opacity: 0;
transition: opacity 0.5s ease-in-out;
}
img.youbou-lazyload.youbou-lazyload__loaded {
opacity: 1;
}
By following these steps, you can effectively implement lazy loading for images on your WordPress website, improving both performance and user experience.