There are a few functions available to retrieve the URL and size of an image in the WordPress Media Library, but few people know that these functions will often lie about an image’s dimensions.
As an example, let’s define a custom image size of 1000 x 1000 cropped, and use image_downsize()
to retrieve the URL and size of an image ID (this example can be used with wp_get_attachment_image_src()
as well). I’ll use list()
in the example, instead of an array variable for the return values, to keep the code more readable. ;-)
add_image_size( 'my-custom-size', 1000, 1000, true );
list( $img_url, $img_width, $img_height, $img_is_intermediate ) = image_downsize( $id, 'my-custom-size' );
WordPress will return a URL for the image and the values of $width / $height may be 1000 / 1000 – it all depends on several factors.
If the image was uploaded when ‘my-custom-size’ existed, then WordPress will return 1000 / 1000 and the correct URL. If ‘my-custom-size’ did not exist when an image was uploaded, then WordPress will return a larger image (if possible) and if it is cropped, the $width / $height values will be 1000 / 1000, even if the image is actually larger. If the larger image is not cropped, then the $width or $height could be 1000, while the other will be a smaller value. And if the original image is smaller than 1000 x 1000, then WordPress returns the largest size it can, which may or may not be cropped.
But the fun doesn’t stop here… ;-) If you’re calling image_downsize()
while you’re on a Post / Page editing page, WordPress will lie about the image’s dimensions if they exceed the width of the editing window, giving you scaled down dimensions instead – it doesn’t matter if you’re planning on using the image within the editor or not.
So, how can we manage this mine-field and get accurate image URLs and dimensions?
The first, and easiest part, is to tell WordPress not to scale down our custom image size on editing pages. We can do this using the ‘editor_max_image_size’ filter.
add_filter( 'editor_max_image_size', array( &$this, 'editor_max_image_size' ), 10, 3 );
public function editor_max_image_size( $max_sizes = array(), $size_name = '', $context = '' ) {
if ( $size_name == 'my-custom-size' )
$max_sizes = array( 0, 0 );
return $max_sizes;
}
The second part will require a bit more code to verify that our custom size exists for that image, and create / re-create it if it doesn’t.
// define our custom size values
$custom_name = 'my-custom-size';
$custom_width = 1000;
$custom_height = 1000;
$custom_crop = true;
// add our custom / intermediate image size
add_image_size( $custom_name, $custom_width, $custom_height, $custom_crop );
// ask wordpress to provide a url to the image size we want
list( $img_url, $img_width, $img_height, $img_is_intermediate ) = image_downsize( $id, $custom_name );
// get all the pre-existing sizes for that image
$img_meta = wp_get_attachment_metadata( $id );
// does our custom size even exist in the image meta data?
// if not, then we will have to create it
if ( empty( $img_meta['sizes'][$custom_name] ) ) {
$is_correct_width = false;
$is_correct_height = false;
// the custom / intermediate size values may have changed over time
// if the custom size exists, then are its values accurate?
} else {
$is_correct_width = ! empty( $img_meta['sizes'][$custom_name]['width'] ) &&
$img_meta['sizes'][$custom_name]['width'] == $custom_width ? true : false;
$is_correct_height = ! empty( $img_meta['sizes'][$custom_name]['height'] ) &&
$img_meta['sizes'][$custom_name]['height'] == $custom_height ? true : false;
}
// check that the width and height values for the original image exist, just in case
if ( empty( $img_meta['width'] ) || empty( $img_meta['height'] ) ) {
echo 'wp_get_attachment_metadata() returned empty original image sizes';
// if the original image size is too small, get the full size image URL instead
} elseif ( $img_meta['width'] < $custom_width && $img_meta['height'] < $custom_height ) {
list( $img_url, $img_width, $img_height, $img_is_intermediate ) = image_downsize( $id, 'full' );
// since wordpress returns image sizes based on the information in the metadata array
// check to see if our intermediate image sizes are correct in the metadata array
// if they're not, then call image_make_intermediate_size() and wp_update_attachment_metadata()
// to create an image using correct dimensions
} elseif ( ( $custom_crop === false && ( ! $is_correct_width && ! $is_correct_height ) ) ||
( $custom_crop === true && ( ! $is_correct_width || ! $is_correct_height ) ) ) {
$fullsizepath = get_attached_file( $id );
$resized = image_make_intermediate_size( $fullsizepath, $custom_width, $custom_height, $custom_crop );
// update the image metadata if successful
if ( $resized !== false ) {
$img_meta['sizes'][$custom_name] = $resized;
wp_update_attachment_metadata( $id, $img_meta );
// get the custom image size again, which should be correct this time
list( $img_url, $img_width, $img_height, $img_is_intermediate ) = image_downsize( $id, $custom_name );
}
}
// after all this, double check that we have what we want
$is_correct_width = $img_width === $custom_width ? true : false;
$is_correct_height = $img_height === $custom_height ? true : false;
// if the custom size is cropped, both width and height must be correct,
// otherwise, only one side needs to be correct
if ( ( $custom_crop === false && ( ! $is_correct_width && ! $is_correct_height ) ) ||
( $custom_crop === true && ( ! $is_correct_width || ! $is_correct_height ) ) ) {
echo 'failure - wordpress could not provide an image large enough';
}