Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 41 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save ctlcltd/1fd7a58722c4e4351073 to your computer and use it in GitHub Desktop.
Save ctlcltd/1fd7a58722c4e4351073 to your computer and use it in GitHub Desktop.
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)

@juliocavalcanti
Copy link

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
Copy link

@leolweb

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

@applesapples1
Copy link

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
Copy link

Thank you very much, you are awesome :-)

@rsharrys
Copy link

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
Copy link
Author

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