I am working on a fairly complex redesign of a wordpress project. Currently I am working on the image implementation. The site is very image heavy and I want to provide the optimal image for each application. I thought about something like this:
1. Orientation
The image can be in landscape, portait or square format. Each has a different max-width. The optimal solution would be to provide a different version for each orientation.
Landscape
Portrait
Square
2. High PPI
I would also like to provide a @2x version of each image:
Landscape
Landscape@2x
Portrait
Portrait@2x
Square
Square@2x
3. Breakpoints
The final site comes with at least four breakpoints. I would also like to optimize the image for each breakpoint:
Breakpoint 1 | Breakpoint 2 | Breakpoint 3 | Breakpoint 4
-------------|--------------|--------------|-------------
Landscape | Landscape | Landscape | Landscape
Landscape@2x | Landscape@2x | Landscape@2x | Landscape@2x
| | |
Portrait | Portrait | Portrait | Portrait
Portrait@2x | Portrait@2x | Portrait@2x | Portrait@2x
| | |
Square | Square | Square | Square
Square@2x | Square@2x | Square@2x | Square@2x
The Problem
In the end, this gives me 24 generated images per image, which is a huge amount of generated data. Two thirds of that data will never be used (the two other orientations) and I would love to strip those out. add_image_size()
does not take the image orientation into account.
Is there any way to only generate the images needed for the orientation of the image?
Update
TL;DR: I may have found a solution, code is at the bottom, further testing tomorrow.
Ok, I took a deep dive into the Wordpress Trac today, and I think I have got it.
It is hard to alter the generation of the add_image_size()
function, so I took the wp_generate_attachment_metadata
hook,
The images get generated in the wp_generate_attachment_metadata()
function. It is hard to alter the function, because the matching wp_generate_attachment_metadata
hook takes place, after the images have been generated.
Still, this was the best hook I have found for this purpose.
I decided to create my own resized copies of the original image (WP_Image_Editor
made that fairly easy) and include the newly generated images in the metadata of the original image.
So far this looks pretty good, except, that the progressbar stays on 100% until the images have been processed. This could be a problem with users leaving the page, before all images have been processed. The second problem was, that the custom generated images do not get deleted, if I delete the attachment. This is because of the get_intermediate_image_sizes()
function, which looks for image sizes, added by add_image_size()
.
I have found the intermediate_image_sizes
hook and want to try to add all possible image sizes to it tomorrow, in the meantime I have a quick solution, which makes use of the delete_attachment
hook.
I will do further testing tomorrow and update this post.
Here is my code so far:
/**
* Generates custom image sizes, depending on the image orientation. Use the wp_generate_attachment_metadata hook!
*/
function r21_create_custom_image_sizes($meta) {
// Initialize variables
global $r21_image_sizes;
$image_sizes = '';
$new_meta = array();
// Generate the full file path for the image
$image['path'] = path_join(wp_upload_dir()['basedir'], $meta['file']);
// Get the dimensions of the original image
list($image['width'], $image['height'], $image['type']) = getimagesize($image['path']);
// Check the image orientation
if ($image['width'] > $image['height']) {
// Landscape
$image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'landscape', true);
} else if ($image['width'] < $image['height']) {
// Portrait
$image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'portrait', true);
} else {
// Square
$image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'square', true);
}
// Iterate through the sizes to be generated
foreach ($image_sizes as $size) {
// TODO: Check if an image in the requested dimensions allready exists.
// Create an instance of WP_Image_Editor for the original image
$new_image = wp_get_image_editor($image['path']);
// Resize the image
$new_image->resize($size['width'], $size['height'], $size['crop']);
// Save new image and store new meta data in variable
$new_image_meta = $new_image->save();
// Reflect back new metadata
$meta['sizes'][$size['name']]['file'] = $new_image_meta['file'];
$meta['sizes'][$size['name']]['width'] = $new_image_meta['width'];
$meta['sizes'][$size['name']]['height'] = $new_image_meta['height'];
$meta['sizes'][$size['name']]['mime-type'] = $new_image_meta['mime-type'];
}
return $meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_create_custom_image_sizes');
/**
* Deletes images, generated by r21_create_custom_image_sizes(). Use the delete_attachment hook!
*/
function r21_delete_custom_image_size_files($post_id) {
$sizes_meta = wp_get_attachment_metadata($post_id)['sizes'];
foreach ($sizes_meta as $size) {
// TODO: Add support for wp_delete_file hook here
@ unlink(path_join(wp_upload_dir()['path'], $size['file']));
}
}
add_action('delete_attachment', 'r21_delete_custom_image_size_files');
max-width:100%; height:auto
isn't solving your problem?