Beautiful, Economic, and Private WordPress image Management

When you’re uploading images to WordPress, WordPress is going to make some changes to your file before it is stored in the WordPress media library. Namely, it is going to resize, smush, and scrape the image for data stored in EXIF. Then WordPress is going to “generate thumbnails.”

Most people are not aware this is being done quietly in the background. Naturally they are confused why their images look differently on their WordPress site to how they look on the camera or desktop. A file is a file is a file, right? Nope. WordPress has wrested some control here. While trying to keep things “sane” for us, they inadvertently create insanity.

Below are some helpful suggestions for taking back control over what WordPress can do to your images. If you see PHP code, don’t worry — it too can be implemented using a plugin1.

File Upload Size

The big image width/height threshhold is set to 2560px. 2560px is pretty darn generous, but if you are trying to upload images with bigger pixel width and height, you can use this PHP filter for WordPress:

add_filter( 'big_image_size_threshold', function( $px, $file, $attachment_id ) { return 10000; } );

If this one-line filter doesn’t work right away, it’s possible it is being superceded by a plugin or theme. You could try re-writing the filter function like this, with a priority of 99, so that it hopefully runs after plugins and themes run their filters:

function top_dog_big_image_size_threshold( $px, $file, $attachment_id ) {
    return 10000;
}
add_filter( 'big_image_size_threshold', 'top_dog_big_image_size_threshold', 99, 3 );

If you’re going to allow huge uploads like that (10,000 pixels wide or high) and display them, you better have great hosting service and paaaaaaatient viewers! If you only needed to do this for one or a few files, and want to be sensible about storage/display of all your other files, your code could be more specific to the file, like this:

function my_specific_big_image_size_threshold( $px, $file, $attachment_id ) {

    /*
     * This function checks for upload/edit of two particular files
     * and allows them to be huge (max 10000 px wide or tall)
     * otherwise it returns the default 2560px
     */
    if ( false !== strpos( $file, 'filethatneedstobehuge.tiff' )
        || false !== strpos( $file, 'other-file-that-needs-to-be-huge.jpeg' )
    ) {
        return 10000;
    }
    return $px;
} 
add_filter( 'big_image_size_threshold', 'my_specific_big_image_size_threshold', 99, 3 );

File Upload Quality

Let’s start here. During upload, WordPress automatically reduces the width and height of your image, and then smushes (processes to reduce extra bytes in the files) the images. This is not a lossless process, meaning by default your images’ quality is reduced to 82% of what you uploaded. That combined with possible conflicts with your theme, which wants to show images at specific ratios, whereas your old theme (which images were sized for) shows images at other ratios, could mean that your WordPress images end up looking low resolution or blurry, or just frustratingly displayed in the wrong aspect ratio. Photographers, you’re warned!

Set JPG/JPEG quality to 100% for any processing during WordPress upload or edit:

add_filter( 'jpeg_quality', function( $quality, $context ) { return 100; } );

Exif and Privacy

WordPress will scrape the image for EXIF data, especially JPG/JPEG or TIFF. EXIF data includes the type of camera you used, its settings, and likely the exact time and (GPS) location where the photograph was taken. Whereas for some sites this can be an asset to organization or display, for others this is a privacy nightmare.

To stop the data scraping, you can use this easy little PHP snippet in your child theme:

/*-------------------------------------------------------------------------------*/
// STOP WordPress looking for EXIF - filtered in wp-admin/includes.image.php
/*-------------------------------------------------------------------------------*/
add_filter( 'wp_read_image_metadata_types', '__return_empty_array' );

If you have privacy concerns–which frankly we all should these days–this snippet will be very useful for your WordPress site. The publication of exact GPS data also leads to personal safety as well as “Leave No Trace” (LNT) concerns.

Nobody needs to know where you were or what device you were carrying and minutiae such as what the camera aperture and exposure settings were. Saving this data in your WP database leads to database bloat which in turn is an environmental concern. So, to take it a bit further and save NO image_meta in your WP postmeta table, use the following code:

/*-----------------------------------------------*/
// STOP WordPress from saving any image meta
/*-----------------------------------------------*/
add_filter( 'wp_read_image_metadata', '__return_empty_array' );

When it’s so easy to stop and clean up with just a couple lines of code, why not?

For what it’s worth the folks over at Short Pixel wrote a post with their method of removing WP image meta from JPG images altogether during the upload process. This might be overkill, since it processes JPG files before they’re processed AGAIN by WP (WordPress by default will mangle your uploads unless you specifically program it not to) and any image optimizing plugins you might be running. Also the Short Pixel code might be confusing to non-programmers. There is a line in there which causes JPG files to be smushed down to 80% of their full quality. That might produce unexpected (and poor) results for people who don’t read code. Instead of running this code, you might choose to use a plugin like Optimus or Short Pixel’s image management plugin offering, which lay out options for you, and which can be turned on/off. Either that, or use a desktop application like ImageOptim which can smush images to your liking and remove EXIF if desired.

Stop Scraping and Storing of Meta with Two Lines

To keep things simple, I really recommend just using the two lines published above. Here they are together:

add_filter( 'wp_read_image_metadata_types', '__return_empty_array' );
add_filter( 'wp_read_image_metadata', '__return_empty_array' );

The first line stops WordPress from even trying to scrape image meta in the first place (CPU saved) and the second line stops WordPress from saving anything extra (even just empty values) to the database.

As far as endangered species (including our privacy) are concerned, that’s a win-win.


Delete Already-Stored Image Meta

If you want to delete existing meta from your stored WordPress images, this script might be helpful. Because the meta isn’t necessarily shared unless via plugin or theme, this script will mostly just cut down on database bulk.

function cleanup_wp_attachment_meta() {
    global $wpdb;


    if ( get_option( 'wp_attachment_meta_cleanup_complete' ) ) {
        return; 
    }

    $batch_size = 75;
    $offset = (int) get_option( 'wp_attachment_meta_cleanup_progress', 0 );

    // Fetch a batch of post_ids using $batch_size as LIMIT and our saved OFFSET
    $post_ids = $wpdb->get_col( $wpdb->prepare(
        "SELECT post_id FROM {$wpdb->postmeta} 
         WHERE meta_key = '_wp_attachment_metadata' 
         ORDER BY post_id ASC 
         LIMIT %d OFFSET %d",
        $batch_size,
        $offset
    ) );

    if ( ! empty( $post_ids ) ) {
        foreach ( $post_ids as $post_id ) {
            $attachment_meta = get_post_meta( $post_id, '_wp_attachment_metadata', true );

            if ( isset( $attachment_meta['image_meta'] ) ) {
                unset( $attachment_meta['image_meta'] );
                update_post_meta( $post_id, '_wp_attachment_metadata', $attachment_meta );
            }
        }

        // Update the progress in wp_options and redirect to start next batch
        update_option( 'wp_attachment_meta_cleanup_progress', $offset + $batch_size );
        wp_safe_redirect( admin_url( 'index.php?cleanup_running=1' ) );
        exit;

    } else {
        // Cleanup is now complete
        // you can delete the 'wp_attachment_meta_cleanup_complete'
        // table option once it is set to true
        update_option( 'wp_attachment_meta_cleanup_complete', true );
        delete_option( 'wp_attachment_meta_cleanup_progress' );

    }
}
add_action( 'admin_init', 'cleanup_wp_attachment_meta' );

Thumbnail Generation

Thumbnail generation refers to the creation of various-sized (by pixel) images to fill specific slots in a WordPress theme. Those slots are usually “thumbnail” “medium” and “large.” Often there is also a “featured image” slot — the one at the top of blog posts and sometimes pages. Those are usually a specific size (actually, aspect ratio or simply ratio) to make the WordPress site “look” a certain way. Maybe they’re mostly square (1:1) and sorta look like Instagram. Maybe the featured images are 4:1 and cropped to center… it’s very unique for each WordPress theme. Troubles start to arise when WordPress site owners keep switching themes.

When a new WordPress theme is activated, WordPress goes about generating thumbnails according to that theme’s specifications. This also happens with some plugin activations. So, in addition to your core WordPress thumbnails (“thumbnail,” “medium” and “large,” set in the WordPress -> Media settings, as well as three other sizes), it’s very likely several other image sizes will be named, and then every image that has ever been stored to your WordPress media library will be processed/resized. This is a big CPU expenditure, and it causes many more files to be stored on your server. When the theme is changed again, it’s highly likely most of those new image files will NEVER be used again. They just sit there, for no reason.

It gets complex to advise here because every theme/plugin will add its own image size suggestions to WordPress. You can see every image size on your WordPress installation using the wp_get_additional_image_sizes() function, but it’s easier to load a plugin. I’ve always liked the AJAX Thumbnail Rebuild plugin. Its core menu (under Tools”) shows you right away which sizes are created currently for every image on your site. The only way to tell which image sizes were created in the past, would be to look into your file system (usually /wp-content/uploads) and see which files seem to be orphans. Conveniently, WordPress names each file size it creates like so:

my-image-file-150x150.jpg
my-image-file-400x300.jpg
my-image-file-800x600.jpg
my-image-file-1536x1536.jpg
my-image-file-2048x2048.jpg
my-image-file.jpg

The file list for the one my-image-file.jpg might be much, much longer if your site has run many themes and plugins, and many of them are likely sitting there burning on a server for no reason. The easiest way to clean old, unwanted files off is using SSH commands sort of like this one:

find wp-content/uploads -type f -name '*-2048x2048*' -exec rm -f {} +

By Golly, don’t use that bash unless you know what you’re doing and are really ready to delete EVERY file that contains the pattern -2048×2048. from your wp-contents/uploads folders. But if you’re getting warnings from your hosting service that you’re running out of disk space or inodes usage is high, running scripts like this to clear out unused image sizes can be your fastest way out.

WordPress quietly creates two larger file sizes in the background to help display medium_large and large files in higher resolution. If you have changed your medium_large and large file sizes from default, then these won’t be quite right. To stop some of these file sizes being generated in the future, you could use the following PHP code snippet in your functions.php file (or by using Code Snippets):

function my_remove_secret_large_image_sizes() {
    remove_image_size( '1536x1536'); // Double default hidden WP medium_large size, 768
    remove_image_size( '2048x2048'); // Double default WP large size, 1024
    /**
     * Then you'd want to add_image_size() to create
     * your @2x of your new medium_large and large sizes
     */
add_action( 'init', 'my_remove_secret_large_image_sizes' );

That said, you need to know what you’re doing here, because if your theme specifically calls for the ‘1536×1536’ image size somewhere in its display (unlikely, but possible), that image will be broken going forward. And if your default medium_large size hasn’t been changed and that is used in display, then the @2x (hi-res retina-style) display won’t work, either. I’ve gotten into the weeds, mostly to show the interplay between WP and themes and what image sizes are stored.

Here’s another example, for Avada theme users:

/*
 * AVADA generates loads of image sizes, and if you're no longer using AVADA
 * it's too late for this particular code,
 * and many many unused image sizes will be sitting on your server
 * Avada even overrides the default WooCommerce image sizes, and will leave
 * those behind, too.
 */
function remove_avada_image_sizes() {
    // If you're not using Avada grids, use the following lines!
    remove_image_size('fusion-200');
    remove_image_size('fusion-400');
    remove_image_size('fusion-600');
    remove_image_size('fusion-800');
    remove_image_size('fusion-1200');

    // If you're not using the Avada Portfolio feature, use the following lines!
    remove_image_size('recent-works-thumbnail'); 
    remove_image_size('portfolio-full');
    remove_image_size('portfolio-one');
    remove_image_size('portfolio-two');
    remove_image_size('portfolio-three');
    remove_image_size('portfolio-five');
add_action( 'init', 'remove_avada_image_sizes' );

If you are migrating away from Avada, be aware it will leave a LOT of unused images on your server.

Understanding how each theme registers and calls for its own image sizes might help you to understand and fix when images appear strange after switching themes or after changing your default WP media sizes in the Media settings. Usually running a plugin like AJAX Thumbnail Rebuild plugin will fix that for you. I also like the Regenerate Thumbnails plugin for the purpose of getting a site’s images ready for a new theme or image size change. (I wish the two plugins would merge since their features are both cool and complimentary!)


If you need more help with this, please just reach out.

  1. If you have no idea how to FTP/SSH and edit your WP theme functions.php file, you could also install any of these code snippets using the WordPress plugin called “Code Snippets.↩︎

Leave a Comment