When we go into Settings >> Media from our WordPress dashboard, we get to set three standard image sizes for our WordPress blog – Thumbnail size, Medium size, and Large size.
Next time we upload an image, the image will be saved in its natural size (i.e., Full size) as well as in the three standard image sizes set above. For example, uploading WordPress-Image1.jpg will save the following files onto our WordPress upload directory –
- WordPress-Image1.jpg (Full size)
- WordPress-Image1-520×320.jpg (Large size)
- WordPress-Image1-420×258.jpg (Medium size)
- WordPress-Image1-150×92.jpg (Thumbnail size)
If we have a theme that supports post thumbnail images, then we may also have an extra Post-thumbnail size as set by our active theme.
- WordPress-Image1-200×123.jpg (Post-thumbnail size)
When we display images in our WordPress blog we want to use an existing image size. This ensures that the client browser does not have to resize the image, which in turn will enhance page speed and image quality.
1. Add a New Image Size
We can add a new image size by using the add_image_size function. This function populates the $_wp_additional_image_sizes global variable with our additional image sizes. Therefore, it needs to be called every time a WordPress page is instantiated.
One way to do this, is to include these function calls into our theme or plugin init action hook.
add_action('init', 'my_init_function'); function my_init_function() { add_image_size( 'shiba_gallery_page', 610, 1000 ); add_image_size( 'noobslide_thumb', 54, 54, TRUE ); }
Now we have added two new image sizes (shiba_gallery_page and noobslide_thumb). However, this only means that newly uploaded images will include those additional sizes. Old images will need to be reprocessed or regenerated in order to add the two new image sizes.
2. Create New Image Size for Old Images
To regenerate the new image sizes for old attachments, we simply need to use two functions –
- wp_generate_attachment_metadata – This function not only generates new metadata for a WordPress image/attachment, but it also regenerates the various image-size files for that attachment. I.e., calling wp_generate_attachment_metadata on an old image file will generate our two new added image sizes for that file. [Function Source]
- wp_update_attachment_metadata – This function updates the image attachment object with updated metadata that includes all of its image sizes and their associated files.
function regenerate_all_attachment_sizes() { $args = array( 'post_type' => 'attachment', 'numberposts' => 20, 'post_status' => null, 'post_parent' => null, 'post_mime_type' => 'image' ); $attachments = get_posts( $args ); if ($attachments) { foreach ( $attachments as $post ) { $file = get_attached_file( $post->ID ); wp_update_attachment_metadata( $post->ID, wp_generate_attachment_metadata( $post->ID, $file ) ); } } }
Lines 2 to 3 – Get the first 20 attachment image objects.
Line 6 – Get the full sized image file associated with the attachment object.
Line 7 – Regenerate all image sizes for the given attachment object and update its metadata.
Note that in the function above we only regenerate image sizes for 20 attachments. If we try to process all of our attachments at once, we will be using up a lot of server resources and likely, the function will exit before it finishes processing all of our files due to insufficient memory.
To keep things manageable, we will want to process our old images in smaller batches. We can achieve this by setting the numberposts and offset arguments in our get_posts function call.
3. Only Generate Files as Needed
The example above regenerates image files for all sizes. However, we need not do this if we are only adding new image sizes. For greater efficiency, we may want to write our own wp_generate_attachment_metadata function so that we only generate new files for our newly added image sizes.
The my_generate_attachment_metadata code below is taken from the wp_generate_attachment_metadata function with some added lines to check for new image sizes.
function my_generate_attachment_metadata( $attachment_id, $file) { $attachment = get_post( $attachment_id ); $metadata = array(); if ( preg_match('!^image/!', get_post_mime_type( $attachment )) && file_is_displayable_image($file) ) { $imagesize = getimagesize( $file ); $metadata['width'] = $imagesize[0]; $metadata['height'] = $imagesize[1]; list($uwidth, $uheight) = wp_constrain_dimensions($metadata['width'], $metadata['height'], 128, 96); $metadata['hwstring_small'] = "height='$uheight' width='$uwidth'"; // Make the file path relative to the upload dir $metadata['file'] = _wp_relative_upload_path($file); // make thumbnails and other intermediate sizes global $_wp_additional_image_sizes; foreach ( get_intermediate_image_sizes() as $s ) { $sizes[$s] = array( 'width' => '', 'height' => '', 'crop' => FALSE ); if ( isset( $_wp_additional_image_sizes[$s]['width'] ) ) $sizes[$s]['width'] = intval( $_wp_additional_image_sizes[$s]['width'] ); // For theme-added sizes else $sizes[$s]['width'] = get_option( "{$s}_size_w" ); // For default sizes set in options if ( isset( $_wp_additional_image_sizes[$s]['height'] ) ) $sizes[$s]['height'] = intval( $_wp_additional_image_sizes[$s]['height'] ); // For theme-added sizes else $sizes[$s]['height'] = get_option( "{$s}_size_h" ); // For default sizes set in options if ( isset( $_wp_additional_image_sizes[$s]['crop'] ) ) $sizes[$s]['crop'] = intval( $_wp_additional_image_sizes[$s]['crop'] ); // For theme-added sizes else $sizes[$s]['crop'] = get_option( "{$s}_crop" ); // For default sizes set in options } $sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes ); // Only generate image if it does not already exist $attachment_meta = wp_get_attachment_metadata($attachment_id); foreach ($sizes as $size => $size_data ) { if (isset($attachment_meta['sizes'][$size])) { // Size already exists $metadata['sizes'][$size] = $attachment_meta['sizes'][$size]; } else { // Generate new image $resized = image_make_intermediate_size( $file, $size_data['width'], $size_data['height'], $size_data['crop'] ); if ( $resized ) $metadata['sizes'][$size] = $resized; } } if ( $attachment_meta['image_meta'] ) $metadata['image_meta'] = $attachment_meta['image_meta']; } return apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id ); }
Added lines:
Lines 36 to 37 – Get the current attachment metadata.
Lines 40 to 43 – If a given size has been previously generated, then skip recreating the resized image file. New files are created during the image_make_intermediate_size function call.
Lines 50-51 – Use existing additional metadata (from exif/iptc files) since our original image has not changed.
4. Remember to Delete Old Image Sizes
As a final note, if we decide to change our existing image sizes, we should remember to delete any old files for sizes that are no longer in use; in addition to recreating new files for our updated sizes.
Dave says
Where exactly in wordpress do you put this add action function to create a new image size?
ShibaShake says
I put it in my child theme. I add functionality to wordpress either through a plugin or through a child theme.
http://codex.wordpress.org/Child_Themes
http://codex.wordpress.org/Writing_a_Plugin
mevsme says
I have few additional sizes, but there’s no any of them in attachment size list, while uploading an image, and selecting which to paste in post? Any ideas why is it so?
Brian says
Thanks for this Shiba – I’m looking for a way to add image sizes that are only generated by uploads happening in the Theme Customizer, do you have any suggestions or direction on how this could be done? I’ve worked with the `intermediate_image_sizes_advanced` filter, which gives me the images I want, the problem is that they don’t appear in the media library so they can’t be deleted by the user, don’t want to create an infinite accumulation of images that the users can’t access (this is for Multisite so administrating this manually for many users would be difficult)!