Resizing of images in WordPress from within a template

WordPress will provide a number of resized images that sit alongside each image that you upload. These are useful to place into posts and pages, archive listings as thumbnails and in themes. Sometimes you may want a specific size for an image to appear in a theme template, but do not want to set it up as one of the “standard” thumbnail sizes that get applied to all uploaded images.

One existing site I worked on did this using the timthumb script. Within the theme templates, thumbnails were delivered like this:

<img src="<?php bloginfo('template_directory');?>/timthumb.php?src=<?php echo $source_image_url;?>&h=90&w=215&zc=1" alt="<?php the_title();?>" />

The upshot of this is that each image resulted in a direct call to a PHP script on the server. The original image URL was passed in as a parameter, as was the new desired size (width and height). The timthumb script would then fetch the image, resize it, then stream the image to the browser.

The script did cache the resized image, which cut down on the amount of CPU needed, but the issue that rose with this hosting was memory usage; calling all these PHP scripts – dozens on some pages – at the same time resulted in many of the scripts running out of memory. The end result is that images on the website would randomly appear and disappear on each page load.

So, we needed a solution. The images needed to be resized on the server, but the resized version also needed to be cached so that it was only resized once. The web page needed to be given a direct URL to the resized image – we do not want to go through a PHP script every time and image was needed.

I found the solution here on stackexchange, and it uses the vt_resize function.

The vt_resize function is added to your theme (in functions.php) and is then available to call in all your theme templates. The equivalent to the above timthumb resize looks like this:

<?php $resizedImage = vt_resize('', $source_image_url, 215, 90, true); ?>
<img src="<?php echo $resizedImage['url']; ?>" alt="<?php the_title();?>" />

The vt_resize function will take the original image, foo.jpg, resize it, then save it back to the same directory as the original image with the size in the name – foo-215×90.jpg. The URL for that resized image is then returned for use in the theme template.

And that was it – problem solved. All instances of timthumb.php in the theme templates (and there were quite a few) were replaced with a call to vt_resize.

The vt_resize function can be downloaded from this gist here. I’ve also reproduced it below, mainly for my own use, but do check the gist link first in case there have been any updates. I do believe image_resize() has been deprecated in WordPress since 3.5. I’m using this script as it appears in WordPress 3.6, and so far it is behaving. A version of vt_resize in a plugin, that can be maintained and kept up-to-date centrally, would be ideal. WordPress does not support dependences, so this kind of thing is unfortunately not encouraged, meaning that every theme that uses this technique will have its own copy of vt_resize. DRY is not something that WordPress generally prescribes to.

<?php
/*
* Resize images dynamically using wp built in functions
* Victor Teixeira
*
* php 5.2+
*
* Exemplo de uso:
*
* <?php
* $thumb = get_post_thumbnail_id();
* $image = vt_resize($thumb, '', 140, 110, true);
* ?>
* <img src="<?php echo $image[url]; ?>" width="<?php echo $image[width]; ?>" height="<?php echo $image[height]; ?>" />
*
* @param int $attach_id
* @param string $img_url
* @param int $width
* @param int $height
* @param bool $crop
* @return array
*/
if(!function_exists('vt_resize')){
    function vt_resize($attach_id = null, $img_url = null, $width, $height, $crop = false){
    if($attach_id){
        // this is an attachment, so we have the ID
        $image_src = wp_get_attachment_image_src($attach_id, 'full');
        $file_path = get_attached_file($attach_id);
    } elseif($img_url){
        // this is not an attachment, let's use the image url
        $file_path = parse_url($img_url);
        $file_path = $_SERVER['DOCUMENT_ROOT'].$file_path['path'];
        // Look for Multisite Path
        if(file_exists($file_path) === false){
            global $blog_id;
            $file_path = parse_url($img_url);
            if(preg_match('/files/', $file_path['path'])){
                $path = explode('/', $file_path['path']);
                foreach($path as $k => $v){
                    if($v == 'files'){
                        $path[$k-1] = 'wp-content/blogs.dir/'.$blog_id;
                    }
                }
                $path = implode('/', $path);
            }
            $file_path = $_SERVER['DOCUMENT_ROOT'].$path;
        }
        //$file_path = ltrim( $file_path['path'], '/' );
        //$file_path = rtrim( ABSPATH, '/' ).$file_path['path'];
        $orig_size = getimagesize($file_path);
        $image_src[0] = $img_url;
        $image_src[1] = $orig_size[0];
        $image_src[2] = $orig_size[1];
    }
    $file_info = pathinfo($file_path);
    // check if file exists
    $base_file = $file_info['dirname'].'/'.$file_info['filename'].'.'.$file_info['extension'];
    if(!file_exists($base_file))
    return;
    $extension = '.'. $file_info['extension'];
    // the image path without the extension
    $no_ext_path = $file_info['dirname'].'/'.$file_info['filename'];
    $cropped_img_path = $no_ext_path.'-'.$width.'x'.$height.$extension;
    // checking if the file size is larger than the target size
    // if it is smaller or the same size, stop right here and return
    if($image_src[1] > $width){
        // the file is larger, check if the resized version already exists (for $crop = true but will also work for $crop = false if the sizes match)
        if(file_exists($cropped_img_path)){
            $cropped_img_url = str_replace(basename($image_src[0]), basename($cropped_img_path), $image_src[0]);
            $vt_image = array(
                'url'   => $cropped_img_url,
                'width' => $width,
                'height'    => $height
            );
            return $vt_image;
        }
        // $crop = false or no height set
        if($crop == false OR !$height){
            // calculate the size proportionaly
            $proportional_size = wp_constrain_dimensions($image_src[1], $image_src[2], $width, $height);
            $resized_img_path = $no_ext_path.'-'.$proportional_size[0].'x'.$proportional_size[1].$extension;
            // checking if the file already exists
            if(file_exists($resized_img_path)){
                $resized_img_url = str_replace(basename($image_src[0]), basename($resized_img_path), $image_src[0]);
                $vt_image = array(
                    'url'   => $resized_img_url,
                    'width' => $proportional_size[0],
                    'height'    => $proportional_size[1]
                );
                return $vt_image;
            }
        }
        // check if image width is smaller than set width
        $img_size = getimagesize($file_path);
        if($img_size[0] <= $width) $width = $img_size[0];
            // Check if GD Library installed
            if(!function_exists('imagecreatetruecolor')){
                echo 'GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library';
                return;
            }
            // no cache files - let's finally resize it
            $new_img_path = image_resize($file_path, $width, $height, $crop);
            $new_img_size = getimagesize($new_img_path);
            $new_img = str_replace(basename($image_src[0]), basename($new_img_path), $image_src[0]);
            // resized output
            $vt_image = array(
                'url'   => $new_img,
                'width' => $new_img_size[0],
                'height'    => $new_img_size[1]
            );
            return $vt_image;
        }
        // default output - without resizing
        $vt_image = array(
            'url'   => $image_src[0],
            'width' => $width,
            'height'    => $height
        );
        return $vt_image;
    }
}
?>


2 Responses to Resizing of images in WordPress from within a template

  1. Jonathan 2014-04-21 at 03:00 #

    Thank, your code has served me much

  2. Kishan 2014-08-29 at 10:15 #

    vt_resize code where the put in my wordpress project ?
    Currently vt_resize.php file include in root and call to theme template file, but not work.
    Pls help me.
    Thank u kishan

Leave a Reply