0

I want to retrieve the closest named image size (e.g. 'thumbnail', 'medium', 'large', 'full', or the name of any custom sizes added with add_image_size()) from an array of width/height values (e.g. array( 150, 150 )). I essentially want to do what wp_get_attachment_image and related functions do but without an actual image.

What I'm hoping for is something like:

$image_size   = get_named_size( array( 150, 150 ) ); // returns 'thumbnail'
$another_size = get_named_size( array( 999999, 999999 ) ); // returns 'full'

It looks like all the resizing magic in the image functions happens in image_downsize(), but as far as I can see everything that happens there relies on an actual image and only returns a new image, not a size, which doesn't really help me.

I can get all the existing sizes using something like the examples here, but comparing my array values with all the existing sizes and finding the closest is going to be a bit cumbersome so I was hoping there was an existing wp function that could help me out.

0

Turns out, image_get_intermediate_size() was easy enough to adapt to my needs. Instead of using wp_get_attachment_metadata to get an existing image's available sizes I use my own function to get all available image sizes (essentially the same as the function proposed here). I then simply return the name rather than the array of meta data.

It works, I need to do some more thorough testing though and may need to make some changes (not sure I actually want to return 'thumbnail' for sizes smaller than 'thumbnail' for example)...

Here is my entire function (it is a static method of a utility class):

/**
 * Return the closest named size from an array of width and height values.
 *
 * Based off of WordPress's image_get_intermediate_size()
 * If the size matches an existing size then it will be used. If there is no
 * direct match, then the nearest image size larger than the specified size
 * will be used. If nothing is found, then the function will return false.
 * Uses get_image_sizes() to get all available sizes.
 *
 * @param  array|string $size   Image size. Accepts an array of width and height (in that order).
 * @return false|string $data   named image size e.g. 'thumbnail'.
 */
public static function get_named_size( $size ) {

    $image_sizes = self::get_image_sizes();
    $data = array();

    // Find the best match when '$size' is an array.
    if ( is_array( $size ) ) {
        $candidates = array();

        foreach ( $image_sizes as $_size => $data ) {

            // If there's an exact match to an existing image size, short circuit.
            if ( $data['width'] == $size[0] && $data['height'] == $size[1] ) {
                $candidates[ $data['width'] * $data['height'] ] = array( $_size, $data );
                break;
            }

            // If it's not an exact match, consider larger sizes with the same aspect ratio.
            if ( $data['width'] >= $size[0] && $data['height'] >= $size[1] ) {
                if ( wp_image_matches_ratio( $data['width'], $data['height'], $size[0], $size[1] ) ) {
                    $candidates[ $data['width'] * $data['height'] ] = array( $_size, $data );
                }
            }
        }

        if ( ! empty( $candidates ) ) {
            // Sort the array by size if we have more than one candidate.
            if ( 1 < count( $candidates ) ) {
                ksort( $candidates );
            }

            $data = array_shift( $candidates );
            $data = $data[0];
        /*
         * When the size requested is smaller than the thumbnail dimensions, we
         * fall back to the thumbnail size to maintain backwards compatibility with
         * pre 4.6 versions of WordPress.
         */
        } elseif ( ! empty( $image_sizes['thumbnail'] ) && $image_sizes['thumbnail']['width'] >= $size[0] && $image_sizes['thumbnail']['width'] >= $size[1] ) {
            $data = 'thumbnail';
        } else {
            return false;
        }

    } elseif ( ! empty( $image_sizes[ $size ] ) ) {
        $data = $size;
    }

    // If we still don't have a match at this point, return false.
    if ( empty( $data ) ) {
        return false;
    }

    return $data;
}

Which I can use (close enough to) how I initially wanted:

$image_size = My_Utility_Class::get_named_size( array( 150, 150 ) ); // returns 'thumbnail'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.