22

I have 1000 images. How can i make wordpress to generate thumb only when needed. For example home slider will only use 10 images i dont want the other 1000 images have that thumbnail generated as its a waste of space and resources.

There is a way to fire add_image_size only when needed ?

Thanks

UPDATE As you mention is not really add_image_size what it needs to be fired. What it would be great is to fire the image resize when i use the_post_thumbnail('slider-thumb'); Maybe this slowdown the first view of the image but that view is usually generated by me when i actually review the post so i dont care.

So between my posts, slider, blog thumbnauls, portfolio thumbnails etc i got 1000 images and i want just 10 images to be resized for the slider i see a lot of wasted resources to generate the thumbnail size for the other 990 images.

Hope its clear now, sorry for my english

3
  • 2
    How is thumbnails generated from the extra 990 images more of a waste of space and resources than 990 unused images in the first place? Wouldn't it make more sense to only upload the images you're actively using?
    – SickHippie
    May 25, 2012 at 22:05
  • Even though more skilled programers are presenting valid arguments against your idea, I find it interesting. I saw some plugins and themes that upload images without generating thumbs (not sure of which right now). But my big doubt about your question is: when are you gonna need it?. What will be the filter?
    – brasofilo
    May 25, 2012 at 22:26
  • 1
    You got me wrong. I use the 990 images in posts, i just dont use the in the home slider. Some of them i need thumbs for the portfolio, some other for blog thumbs, etc
    – chifliiiii
    May 25, 2012 at 22:55

11 Answers 11

14

Take a look at Otto's Dynamic Image Resizer plugin

This plugin changes the way WordPress creates images to make it generate the images only when they are actually used somewhere, on the fly. Images created thusly will be saved in the normal upload directories, for later fast sending by the webserver. The result is that space is saved (since images are only created when needed), and uploading images is much faster (since it's not generating the images on upload anymore).

3
  • 2
    Note that that plugin has a problem with adding images to old posts. Patches welcome.
    – Otto
    May 26, 2012 at 2:18
  • Thats exactly what i was looking for. I will give it a try. So it only works on new posts?
    – chifliiiii
    May 26, 2012 at 16:04
  • 4
    To those coming across this post now, here's a similar plugin that appears to be actively being developed: wordpress.org/plugins/fly-dynamic-image-resizer
    – Tim Malone
    Mar 23, 2016 at 1:08
8

Put this in your theme functions file. It will stop Wordpress from creating anything but the 3 default sizes when uploading.

When an image is then requested in a particular size, which is not yet generated, it will be created only that once.

        add_filter('image_downsize', 'ml_media_downsize', 10, 3);
        function ml_media_downsize($out, $id, $size) {
            // If image size exists let WP serve it like normally
            $imagedata = wp_get_attachment_metadata($id);
            if (is_array($imagedata) && isset($imagedata['sizes'][$size]))
                return false;

            // Check that the requested size exists, or abort
            global $_wp_additional_image_sizes;
            if (!isset($_wp_additional_image_sizes[$size]))
                return false;

            // Make the new thumb
            if (!$resized = image_make_intermediate_size(
                get_attached_file($id),
                $_wp_additional_image_sizes[$size]['width'],
                $_wp_additional_image_sizes[$size]['height'],
                $_wp_additional_image_sizes[$size]['crop']
            ))
                return false;

            // Save image meta, or WP can't see that the thumb exists now
            $imagedata['sizes'][$size] = $resized;
            wp_update_attachment_metadata($id, $imagedata);

            // Return the array for displaying the resized image
            $att_url = wp_get_attachment_url($id);
            return array(dirname($att_url) . '/' . $resized['file'], $resized['width'], $resized['height'], true);
        }


        add_filter('intermediate_image_sizes_advanced', 'ml_media_prevent_resize_on_upload');
        function ml_media_prevent_resize_on_upload($sizes) {
            // Removing these defaults might cause problems, so we don't
            return array(
                'thumbnail' => $sizes['thumbnail'],
                'medium' => $sizes['medium'],
                'large' => $sizes['large']
            );
        }
5
  • This filer should be standard in WordPress. Why generate every size for every image? I am adding this code to my custom themes. Thanks
    – Michaelkay
    May 23, 2014 at 17:19
  • 2
    Nice but now it still will generate all the images if i need only one custom size..
    – Gijs
    Jan 10, 2015 at 19:44
  • It happens when i use image objects from advanced custom fields
    – Gijs
    Jan 10, 2015 at 20:26
  • Doesn't work IF add_image_size was previously defined with the image dimensions just changed Jan 21, 2015 at 10:19
  • @Michaelkay there is a performance penalty in this approach. When images are uploaded and then generated for every size, means the uploader is the one with patience. This code makes your visitors have to have more patience, and Google has proven sites that take longer than 2s to load, drops 50% of people. Also if your site has hundreds of concurrent visits, this will take down your servers. Mar 8, 2019 at 16:01
4

Unfortunately @Patrick's answer breaks the srcset functions introduced in WP 4.4. Fortunately, we just need to add two additional functions!

First, we need to temporarily re-introduce all of the registered thumbnail sizes to the image metadata so they can be considered:

function bi_wp_calculate_image_srcset_meta($image_meta, $size_array, $image_src, $attachment_id){
    //all registered sizes
    global $_wp_additional_image_sizes;

    //some source file specs we'll use a lot
    $src_path = get_attached_file($attachment_id);
    $src_info = pathinfo($src_path);
    $src_root = trailingslashit($src_info['dirname']);
    $src_ext = $src_info['extension'];
    $src_mime = wp_check_filetype($src_path);
    $src_mime = $src_mime['type'];
    $src_base = wp_basename($src_path, ".$src_ext");

    //find what's missing
    foreach($_wp_additional_image_sizes AS $k=>$v)
    {
        if(!isset($image_meta['sizes'][$k]))
        {
            //first, let's find out how things would play out dimensionally
            $new_size = image_resize_dimensions($image_meta['width'], $image_meta['height'], $v['width'], $v['height'], $v['crop']);
            if(!$new_size)
                continue;
            $new_w = (int) $new_size[4];
            $new_h = (int) $new_size[5];

            //bad values
            if(!$new_h || !$new_w)
                continue;

            //generate a filename the same way WP_Image_Editor would
            $new_f = wp_basename("{$src_root}{$src_base}-{$new_w}x{$new_h}." . strtolower($src_ext));

            //finally, add it!
            $image_meta['sizes'][$k] = array(
                'file'      => $new_f,
                'width'     => $new_w,
                'height'    => $new_h,
                'mime-type' => $src_mime
            );
        }
    }

    return $image_meta;
}
add_filter('wp_calculate_image_srcset_meta', 'bi_wp_calculate_image_srcset_meta', 10, 4);

Then we need to run through the matches and generate any missing thumbnails:

function bi_wp_calculate_image_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id){

    //get some source info
    $src_path = get_attached_file($attachment_id);
    $src_root = trailingslashit(pathinfo($src_path, PATHINFO_DIRNAME));

    //the actual image metadata (which might be altered here)
    $src_meta = wp_get_attachment_metadata($attachment_id);

    //an array of possible sizes to search through
    $sizes = $image_meta['sizes'];
    unset($sizes['thumbnail']);
    unset($sizes['medium']);
    unset($sizes['large']);

    $new = false;

    //loop through sources
    foreach($sources AS $k=>$v)
    {
        $name = wp_basename($v['url']);
        if(!file_exists("{$src_root}{$name}"))
        {
            //find the corresponding size
            foreach($sizes AS $k2=>$v2)
            {
                //we have a match!
                if($v2['file'] === $name)
                {
                    //make it
                    if(!$resized = image_make_intermediate_size(
                        $src_path,
                        $v2['width'],
                        $v2['height'],
                        $v2['crop']
                    )){
                        //remove from sources on failure
                        unset($sources[$k]);
                    }
                    else
                    {
                        //add the new thumb to the true meta
                        $new = true;
                        $src_meta['sizes'][$k2] = $resized;
                    }

                    //remove from the sizes array so we have
                    //less to search next time
                    unset($sizes[$k2]);
                    break;
                }//match
            }//each size
        }//each 404
    }//each source

    //if we generated something, update the attachment meta
    if($new)
        wp_update_attachment_metadata($attachment_id, $src_meta);

    return $sources;
}
add_filter('wp_calculate_image_srcset', 'bi_wp_calculate_image_srcset', 10, 5);
1
  • Just a heads-up to let you know that this will break hard-cropping! It took me hours to find out that this was the culprit. I'm working on a solution... Feb 22, 2018 at 7:25
1

Actually, add_image_size() doesn't generate the thumbnail, it just registers an image size as available to WordPress.

Typically, thumbnails are generated when the image is first uploaded. It's an automatic process so you don't have to worry about generating them later. Think of it this way - if it takes 1-2s to generate a thumbnail on a slow server, and you wait until it's requested, you force the requestee to wait an additional 1-2s per image to see the content. It's much easier to do this ahead of time - i.e. when the image is uploaded.

At the same time, if you absolutely must process the thumbnails at a different time, you might want to take a look at Viper's Regenerate Thumbnails plugin. It uses an on-demand action to regenerate all of your image thumbnails ... but you could use similar code to generate thumbnails only when needed.

2
  • I think you didn't get the point. He wants to control for which images a thumbnails is needed. So some images don't need to be resized at all.
    – imrek
    Mar 21, 2015 at 16:55
  • Most people test pages when the insert photos (I feel pretty save saying all) They will cause the generation of the files needed that once and your done. In my case, I have a header image size registered. About 1 in 20 images I upload are actually for the header. So 19 in 20 images in my library is a waste of space.
    – JpaytonWPD
    Dec 5, 2016 at 0:55
1

There is a way to fire add_image_size only when needed ?

Not exactly. But you can filter the list of registered sizes right before the thumbnails are generated. The wp_generate_attachment_metadata() function (which calls the function that generates the thumbnails) has a filter called "intermediate_image_sizes_advanced", which lets you manipulate the array of sizes just before the files are generated. You could use this filter whenever you're adding an image of a certain "type", and then remove it immediately after.

I guess your biggest challenge would be to figure out how to differentiate between images that need the extra sizes, and those that don't.

1
  • 1
    i would have to add an option or checkbox when i upload media to choose wich thumbs i want to generate for example. Sounds good but i got not clue on how to do that
    – chifliiiii
    May 25, 2012 at 23:19
1

You can use my (not Ottos) "Dynamic Image Resize" 1) plugin.

“Dynamic Image Resize” is a WordPress (MU-)plugin that offers a shortcode and a template tag to resize images “on the flight” without the need of TimThumb, but with WP core functions.

The plugin comes with a template tag and a shortcode as well.

1) Just found out about Ottos plugin. Naming collision wasn't intended.

1

You can try this plugin: https://wordpress.org/plugins/optimize-images-resizing

It resizes images based on your registered image size, but only when needed. Also can cleanup existing image sizes so they can regenerate.

0

WP Performance Pack plugin offers "improved image handling", which is based on Ottos Dynamic Image Resizer, but includes many improvements, e.g.: First of all it's compatible with the latest WordPress Version (3.9.1), uses WP_Image_Editor, saving of thumbnails can be turned off (but they can be cached and CDN Support is on ist way), Regenerate Thumbails integration (to delete existing thumbnails) and some more.

0

Here yet another approach: Its hooks into the 404 HTTP error handling. That is, when thumbnail is not available, find the original image and create the thumbnail. Note that this does not really solve your problem, as it does not preven thumbnail generation during upload.

Note also that this plugin might be used by malicious users to create any number of thumbnails and thus to exhaust your disk space.

Note: This plugin can easily be installed using Pluginception.

<?php
/*
Plugin Name: Create thumbnails on demand
Plugin URI: 
Description: Create thumbnails instead of showing 404. Use in combination with "Broken Link Checker" to create all missing thumbnails.
Version: 0.1
Author: Jack Miller
Author URI: 
License: 
License URI: 
*/
add_filter('status_header', 'createThumbIf404');
function createThumbIf404($httpCodeString) //e.g. HTTP/1.1 200 OK 
{
    global $wp_query;
    error_reporting(E_ALL);
    ini_set('display_errors', 1);

    $httpCode = explode(" ", $httpCodeString);
    $httpCode = $httpCode[1];
    if ($httpCode == "404") {
        $requestUri = $_SERVER["REQUEST_URI"];
        $regex = '/^\/(wp-content\/uploads\/(?:[a-zA-Z0-9]*\/){2})(.*)-(.*)x(.*)\.jpg$/';
        preg_match($regex, $requestUri, $groups);
        if (sizeof($groups) === 5) {
            $baseDir  = $groups[1];
            $baseName = $groups[2];
            $sizeX    = $groups[3];
            $sizeY    = $groups[4];

            $oriImg = ctod_checkFile($baseDir, $baseName);
            if ($oriImg != null) {

                $image = wp_get_image_editor($baseDir . $oriImg);
                if (!is_wp_error($image)) {
                    $image->resize($sizeX, $sizeY, true);
                    $thumb = $baseDir . $baseName . '-' . $sizeX . 'x' . $sizeY . '.jpg';
                    $image->save($thumb);
                    ctod_sendImageAndExit($thumb);
                }
            }
        }
    }
}
//finds original image within $baseDir with $baseName.
//Returns file name including extension of original image or null.
function ctod_checkFile($baseDir, $baseName)
{
    $arr = array(
        ".jpg",
        ".JPG",
        ".jpeg",
        ".JPEG"
    );
    foreach ($arr as &$ext) {
        if (file_exists($baseDir . $baseName . $ext)) {
            return $baseName . $ext;
        }
    }
    return null;
}
//Read file at $path from disk and return it as HTTP JPG image request.
function ctod_sendImageAndExit($path)
{
    $fp = fopen($path, 'rb');
    header("Content-Type: image/jpeg");
    header("Content-Length: " . filesize($path));
    fpassthru($fp);
    exit();
}
1
  • I like this solution. Did you ever adapt it to include more image types?
    – kalligator
    May 8, 2021 at 10:53
0

On other places all made sizes will work but only on the media upload if you want the specific size to upload then below is the code for it. Here is the link for more description - https://developer.wordpress.org/reference/hooks/wp_handle_upload_prefilter/

add_filter('wp_handle_upload_prefilter', 'custom_upload_filter' );
 
function custom_upload_filter( $file ) {
   foreach ( get_intermediate_image_sizes() as $size ) {
        if ( !in_array( $size, array( 'thumbnail', 'medium', 'medium_large', 'large' ) ) ) {
            remove_image_size( $size );
        }
    }
    return $file;
}
-1

You can try also Aqua Resizer - https://github.com/syamilmj/Aqua-Resizer/

It's just a one file.

You can use it like this:

$img_src = aq_resize( $img_src, $width = null, $height = null, $crop = null, $single = true, $upscale = false );

$img_src = aq_resize( $img_src, 150, 150); // resized
$img_src = aq_resize( $img_src, 150, 150, true); // cropped
$img_src = aq_resize( $img_src, 150, 150, null, null, true); // image with 120x120 for example will be upscaled up to 150x150
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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