Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to easily generate low quality image placeholders (lqip) in WordPress

How to easily generate low quality image placeholders (lqip) in WordPress

I have made this function using the WP_Image_Editor class and I have filtered through the "wp_generate_attachment_metadata" hook. You can modify the "theme" namespace into function names with your theme name or in anyway you like.

Applying the filter directly to wp_generate_attachment_metadata the image placeholders are auto added into WordPress metadata, so when your add/modify/delete an image (or regenerate it via a plugin), it accomplishes to modify also to the image placeholders.

The use of the native theme support can prevent the generation of lqip or target specific image sizes to generate.

It contains an hook filter lqip_quality to modify the quality without have to modify the function.

This function could be modified and extended for example to differentiate quality for each size or apply filtering to a specific image size, etc.

Theme initialization

/**
 * Your theme setup
 */
function theme_setup() {
	// if you want to generate lqip for all the image sizes
	add_theme_support( 'lqip' );

	// if you want to specify what image sizes to generate lqip
	add_theme_support( 'lqip', array( 'thumbnail', 'medium' ) );
}
add_action( 'after_setup_theme', 'theme_setup' );

My simple function to make lqip

/**
 * Easy adds lqip to WordPress
 * 
 * @global array $_wp_theme_features
 * @global array $_wp_additional_image_sizes
 * @param array $metadata
 * @param int $attachment_id
 * @return array $metadata
 */
function theme_lqip_support( $metadata, $attachment_id ) {
	global $_wp_theme_features;

	if ( ! isset( $_wp_theme_features['lqip'] ) )
		return $metadata;

	global $_wp_additional_image_sizes;

	if ( is_array( $_wp_theme_features['lqip'] ) ) {
		$image_sizes = $_wp_theme_features['lqip'][0];
	} else {
		$image_sizes = get_intermediate_image_sizes();
		$image_sizes = apply_filters( 'intermediate_image_sizes_advanced', $image_sizes );
	}

	$file = get_attached_file( $attachment_id );
	$quality = apply_filters( 'lqip_quality', 10 );

	if (
		preg_match( '!^image/!', get_post_mime_type( $attachment_id ) ) &&
		file_is_displayable_image( $file )
	) {
		$path_parts = pathinfo( $file );

		foreach ( $image_sizes as $size ) {
			if ( isset( $metadata['sizes'][$size] ) ) {
				if ( isset( $_wp_additional_image_sizes[$size]['width'] ) )
					$width = intval( $_wp_additional_image_sizes[$size]['width'] );
				else
					$width = get_option( "{$size}_size_w" );

				if ( isset( $_wp_additional_image_sizes[$size]['height'] ) )
					$height = intval( $_wp_additional_image_sizes[$size]['height'] );
				else
					$height = get_option( "{$size}_size_h" );

				if ( isset( $_wp_additional_image_sizes[$size]['crop'] ) )
					$crop = intval( $_wp_additional_image_sizes[$size]['crop'] );
				else
					$crop = get_option( "{$size}_crop" );

				$new_size = $size . '-lqip';
				$filename = str_replace(
					'.' . $path_parts['extension'],
					'-lqip.' . $path_parts['extension'],
					$metadata['sizes'][$size]['file']
				);
				
				$image = wp_get_image_editor( $file );
				$image->resize( $width, $height, $crop );
				$image->set_quality( $quality );
				$image->save( $path_parts['dirname'] . '/' . $filename );

				if ( ! is_wp_error( $image ) ) {
					$metadata['sizes'][$new_size] = $metadata['sizes'][$size];
					$metadata['sizes'][$new_size]['file'] = $filename;
				}
			}
		}
	}

	return $metadata;
}
add_filter( 'wp_generate_attachment_metadata', 'theme_lqip_support', 10, 2 );

Debug

To debug the filter during image upload or manipulation you can add this code in the function theme_lqip_support before the return or inside the foreach loop.

A fresh dump.txt file will be created in the same directory files where stored.

	file_put_contents( $path_parts['dirname'] . '/dump.txt', print_r(
		array(
			'_wp_theme_features' => $_wp_theme_features,
			'_wp_additional_image_sizes' => $_wp_additional_image_sizes,
			'image_sizes' => $image_sizes,
			'metadata' => $metadata,
			'attachment_id' => $attachment_id,
			'file' => $file,
			'quality' => $quality,
			'path_parts' => $path_parts,
			'image' => $image,
			'new_size' => $new_size,
			'filename' => $filename
		)
	, true ) );

Feedbacks and suggestions will be appreciated :)

Tested up to: WordPress 4.0 License: MIT MIT License (Expat)

@bastisteiner

This comment has been minimized.

Copy link

@bastisteiner bastisteiner commented Feb 24, 2016

Thank you for this. Really helpful inspiration.

Just two remarks:

  • the action hook to add the theme support is "after_setup_theme" not "after_theme_setup"
  • I would suggest adding the width and height of the newly created image to the metadata like this:
$metadata['sizes'][$new_size]['width'] = $width;
$metadata['sizes'][$new_size]['height'] = $height;

This way other plugins/functions depending on dimensions don't throw an error.

@juliocavalcanti

This comment has been minimized.

Copy link

@juliocavalcanti juliocavalcanti commented Aug 15, 2016

Hey! Very nice solution! But, I wanted to generate the lqip version only for the original image instead of other sizes. How could I do this?

@studio404pl

This comment has been minimized.

Copy link

@studio404pl studio404pl commented Feb 17, 2017

@leolweb

really nice script, but if it works backward with existing media images for example with thumbnail regenerator?

@applesapples1

This comment has been minimized.

Copy link

@applesapples1 applesapples1 commented Aug 17, 2017

What should I be expecting to see when running this script? It appears that a new image will be created with -lqip added as a suffix, but I'm not seeing any new images created, period.

@bracketsberlin

This comment has been minimized.

Copy link

@bracketsberlin bracketsberlin commented Jul 15, 2019

Thank you very much, you are awesome :-)

@rsharrys

This comment has been minimized.

Copy link

@rsharrys rsharrys commented Sep 9, 2021

How do I exclude the (lqip) format from the picture gallery? Currently it overwrites srcset medium size 300px -> 300px lqip.

<img width="768" height="512" src="http://site/image-768x512.jpg" class="attachment-medium_large size-medium_large wp-post-image lazyload" alt="" loading="lazy" sizes="(max-width: 768px) 100vw, 768px" srcset="http://site/image-768x512.jpg 768w, http://site/image-300x200-lqip.jpg 300w, http://site/image-1024x683.jpg 1024w, http://site/image-1536x1024.jpg 1536w, http://site/image.jpg 1600w">

@ctlcltd

This comment has been minimized.

Copy link
Owner Author

@ctlcltd ctlcltd commented Sep 29, 2021

@rsharrys It's been a while since I wrote this script. Changes have been introduced in the meantime. You could try using this filter:

add_filter( 'wp_image_resize_identical_dimensions', '__return_true' );

otherwise you could modify the script to not allow images of that resolution to be overwritten.

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