Downsizing Many Large Images Attached to Posts, in Bulk?

(Moderator’s note: The original title was: “Shrink full size images in post”)

I built a WordPress site for someone and they entered a ton of posts with images that are wider than the content area. Is there a way to shrink all of the image attachements to use a max width? They are entered as “full size”, not as thumbnail, medium, etc.

Related posts

Leave a Reply

4 comments

  1. Great question! WordPress lacks some of the higher level imaging management features that would make it file maintenance like you need so much easier. The core WordPress team has been threatening to add enhance image features for many versions; eventually they might actually do it! Until then you’ll have to use a patchwork of plugins and/or custom code.

    More good news and bad news: The good news is WordPress combined with PHP has tons of lower level imaging handling features but the bad news is it has tons of lower level imaging handling features from which you have to decide which to use! A while back I posted a list of image handling functions found in WordPress and if you’ll scan it you’ll probably see there are several different ways to skin this cat.

    That said, I picked one approach and it follows below with copious comments rather than explain here in the text. You can just copy it to the root of your website as something like /downsize-images.php and call it from your browser. If it times out, don’t worry; I wrote it to keep track of what it had already done so just keep running it until you see it print “Done!”

    NOTE: You need to set the constant MAX_RESIZE_IMAGE_TO to whatever you want your maximum dimension to be; my example used 640 pixels. After it runs you’ll have a bunch of image files with an extension of .save appended. Once you are happy that it ran like you wanted you can just delete those .save files. I didn’t automatically delete them in case something went wrong with the script.

    (IMPORTANT: Be SURE TO BACKUP both your database and your upload directory BEFORE you run this. It worked on my machine but you might have something I didn’t test and it might cause corruption so backup! DO NOT come back later and say I didn’t warn you!!!):

    <?php
    
    include "wp-load.php";                 // Need this to load WordPress core
    include "wp-admin/includes/image.php"; // Needed for wp_create_thumbnail()
    
    define('MAX_RESIZE_IMAGE_TO',640);     // SET YOUR MAX DIMENSION HERE!!!!
    
    // Check our "queue" to see if we've previously only run to partial competion.
    $attachment_ids = get_option('attachment_ids_to_resize');
    if ($attachment_ids=='Done!') { // Make sure we don't do it again
      echo 'Already done.';
    } else {
      if (empty($attachment_ids)) { // If this is the first time, this array will be empty. Get the IDs.
        global $wpdb;
        $attachment_ids = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type='attachment'");
      }
      foreach($attachment_ids as $index => $attachment_id) {
        // Get metadata: [width,height,hwstring_small,file,sizes[file,width,height],image_meta[...]]:
        $metadata = wp_get_attachment_metadata($attachment_id);
        // Get upload_dir: [path,url,subdir,basedir,baseurl,error]:
        $upload_dir = wp_upload_dir();
        // Get full path to original file
        $filepath = "{$upload_dir['basedir']}/{$metadata['file']}";
        // Make a smaller version constrained by largest dimension to MAX_RESIZE_IMAGE_TO
        $smaller_file = wp_create_thumbnail( $filepath, MAX_RESIZE_IMAGE_TO);
        // If the file was really created
        if (@file_exists($smaller_file)) {
          // Append a ".save" to original file name, just in case (you can manually delete *.save)
          rename($filepath,"{$filepath}.save");
          // Get this smaller files dimensions
          list($width,$height) = getimagesize($smaller_file);
          // Strip the base directory off the filename (i.e. '/Users/username/Sites/sitename/wp-content/uploads/')
          $metadata['file'] = str_replace("{$upload_dir['basedir']}/",'',$smaller_file);
          $metadata['height'] = $height;
          $metadata['width'] =  $width;
          // Get the the small size, 128x96 or smaller if need be
          list($uwidth,$uheight) = wp_constrain_dimensions($metadata['width'], $metadata['height'], 128, 96);
          $metadata['hwstring_small'] = "height='$uheight' width='$uwidth'";
          // Make sure none of the sizes are larger than the new size
          foreach($metadata['sizes'] as $size => $size_info) {
            if (intval($size_info['height'])>intval($height) ||
                intval($size_info['width'])>intval($width)) {
              // If too large get the full file path of the sized image
              $old_file = "{$upload_dir['path']}/{$size_info['file']}";
              // Tack a ".save" extension on it, just in case (you can manually delete *.save)
              rename($old_file,"{$old_file}.save");
              // Remove it from the metadata since it's too large
              unset($metadata['sizes'][$size]);
            }
          }
          // Update the attachement metadata with the new smaller values
          wp_update_attachment_metadata($attachment_id,$metadata);
          // Update the name of the other place the orginal file name is stored
          update_attached_file($attachment_id,$metadata['file']);
        }
        // Remove this attachment from our "queue"
        unset($attachment_ids[$index]);
        // Save the new smaller "queue" in case we need to run this again.
        update_option('attachment_ids_to_resize',$attachment_ids);
      }
      // If we've actually processed them all
      if (count($attachment_ids)==0) {
        // Store a marker so we won't accidentally run this again
        update_option('attachment_ids_to_resize','Done!');
      }
      echo 'Done!';
    }
    
  2. You can do a max-width. In the functions.php do something similar to what is done in Twenty Ten.

    /**
     * Set the content width based on the theme's design and stylesheet.
     *
     * Used to set the width of images and content. Should be equal to the width the theme
     * is designed for, generally via the style.css stylesheet.
     */
    if ( ! isset( $content_width ) )
        $content_width = 640;
    

    Set the size in you style.css

    #content img {
    max-width: 640px;
    }
    

    In Settings->Media change the max size to your maximum width, in this example 640.

    You need to do all of these things for it to work. Then WP will create a “large” image that is the correct size for the webpage. The user will then have to insert the “large” image rather than the full size image.


    Then use Regenerate Thumbnails plugin by Viper007Bond. http://www.viper007bond.com/wordpress-plugins/regenerate-thumbnails/ which will regenerate all the new image sizes.


    Not sure how to deal with the images that have already been inserted at “full size”, aside from re-inserting them manually.

    Not sure how the images are being displayed in the post, but you can retrieve a specified size image by using wp_get_attachment_image() – see the codex – I would have to know how the images are being displayed to give more detailed answer.

  3. I would suggest you fix this using the operating system or software.

    What i would do is download the images from hosting, use automator in my OSX or record a some photoshop macro to resize the images or use some mass image resizer – resize, reupload

    If the blog is on your own server and you have command line access, i guess it would be easier to resize using some commands (i need more details on ur system to be able to tell)

    you can also try writing some php script that resize the images – it should be pretty easy to do – there are bunch of image resizing scripts around if you google (make sure you run it on some test images first before ruining the whole gallery)

    and good luck 🙂

  4. you could use the gd extension in php, or imagemagick binaries on the linux cli. timthumb.php is widely used for thumbnails etc, you could do something with that as well. ideally for the next post you’ll make sure the client does it properly, instead of you creating a plugin that intercepts all the img calls, and runs em through your resize filter :).