Image Sizes
In this tutorial we are going to talk about image sizes in WordPress. Well, but what image sizes are exactly?
All right, if you open your WordPress /wp-content/uploads
directory, you might find something like this there:

As you can see, an image you’ve uploaded once was duplicated multiple times with different image sizes. And in this case I am just using default WordPress theme with no plugins installed.
Users who don’t know what is the thing – image sizes in WordPress could be terrified by what they see in uploads directory.
The key idea is that when you upload an original image (especially unoptimized, up to 10MB) it would stupid to use this exact file everywhere on the website. Maybe you have a list of recent posts displayed somewhere with 100×100px thumbnails and what about srcset
and sizes
attributes of course?
A great example is the list of products in WooCommerce in admin area:

Needless to say that using image resizing software is also not a great idea because it will create huge performance issues on your server.
That’s why WordPress creates so many image copies and in this tutorial we are going to learn to manage them.
Default Image Sizes
Image size | Description |
---|---|
thumbnail | Thumbnail size from Settings > Media. |
medium | Medium size from Settings > Media. |
medium_large | This image size appeared in WordPress 4.4 with responsive images feature and is used in srcset attribute. It has a fixed width of 768px and proportional height. |
large | Large size from Settings > Media. |
1536x1536 and 2048x2048 | These image sizes appeared in WordPress 5.3, their goal is also to generate more suitable srcset and sizes attributes on larger, high-density devices. |
-scaled | This is not exactly an image size but since WordPress 5.3 if you upload an image and its height or width is more than 2560px (can be changed with big_image_size_threshold hook), then WordPress will create its smaller copy with -scaled suffix. |
full | The original image. |
Thumbnail, medium and large sizes can be managed in Settings > Media:

Registering Custom Image Sizes
1. add_image_size()
Registering a custom image size for your need is as easy as to use add_image_size()
function inside functions.php
or wherever you need. But there could be a couple of nuances, we are going to discuss them in just a little bit.
Example of registering a custom image size:
add_action( 'after_setup_theme', function() {
add_image_size( 'my-image-size-name', 200, 200, array( 'left', 'top' ) );
} );
A couple moments to keep in mind:
- It is recommended to use
add_image_size()
function insideafter_setup_theme
hook, but usually it works great without it as well. - The first three parameters of the function are quite straightforward, the fourth argument is the most interesting one, it defines the rules how images with different ratio should be cropped. To keep the things simple I decided to use a square size in this example. So, it is easy to say, that if an original image is horizontal, the left part of the image will remain untouched, but the right part will be cropped, and the same I can say about vertical images – the bottom part of images will be cropped. But you can set this argument to
false
and images won’t be cropped, only resized. Of course you can read more about function parameters in the official documentation. - Don’t create a lot of custom image sizes though because more image sizes you create – more files will be in your uploads folder and more time it will need to upload (and process) an image to your site.
2. Add your custom image size selection to Media Uploader and Block Editor
When you insert images to posts, WordPress allows you to choose what image size to use:

But what should we do so our custom image size appears there? The hook image_size_names_choose
should help you with that.
add_filter( 'image_size_names_choose', function( $sizes ) {
// $sizes[ 'image size name' ] = 'Label (anything)';
$sizes[ 'my-image-size-name' ] = 'Misha size';
return $sizes;
} );
3. Regenerate old media
The key moment you should always remember is when you create or remove image sizes the new file copies are going to be created only at the moment of uploading an image.
What should we do in this case? Reupload images every time? Of course not, there are a plenty of plugins for that purpose. For example these ones I used:
- AJAX Thumbnail Rebuild,
- Force Regenerate Thumbnails.
In some cases you may want to regenerate thumbnail programmatically, you can do it with the function below:
function rudr_regenerate_sizes_for_image( $attachment_id ) {
$path = get_attached_file( $attachment_id );
if( $path ) {
wp_update_attachment_metadata(
$attachment_id,
wp_generate_attachment_metadata( $attachment_id, $path )
);
}
}
Conditional image sizes registration – how to create certain image sizes for custom post types only?
Let’s imagine for a moment that your website has 10 registered custom post types, and each of them uses 2-3 image sizes on the website pages. It is easy to understand that when we upload any picture WordPress is going to create 20-30 copies of it!
There is no way to use add_image_size() for a custom post type but here is a tricky piece of code that solves this problem. This code tells WordPress when a file for a specific image size should be created and when it shouldn’t.
Both intermediate_image_sizes
and intermediate_image_sizes_advanced
hooks are ok for this task. A super simple example is below, files for my-image-size-name
image size won’t be created for images, uploaded for a custom post type page
.
add_filter( 'intermediate_image_sizes_advanced', function( $sizes ){
$post_id = isset( $_REQUEST[ 'post_id' ] ) ? $_REQUEST[ 'post_id' ] : null;
if( ! $post_id ) {
return $sizes;
}
if( 'page' === get_post_type( $post_id ) ) {
unset( $sizes[ 'my-image-size-name' ] );
}
return $sizes;
} );
A little bit more complicated example, but it is also correct:
add_filter( 'intermediate_image_sizes', function( $sizes ){
// $sizes - all the image sizes in an array
// Array ( [0] => thumbnail [1] => medium [2] => large [3] => post-thumbnail )
$post_id = isset( $_REQUEST[ 'post_id' ] ) ? $_REQUEST[ 'post_id' ] : null;
if( ! $post_id ) {
return $sizes;
}
$post_type = get_post_type( $post_id );
foreach( $sizes as $key => $value ) {
switch( $post_type ) {
case 'regionfeatured' : {
unset( $sizes[ $key ] );
break;
}
case 'region' : {
if( ! in_array( $value, array( 'regionfeatured', 'misha335' ) ) ) {
unset( $sizes[ $key ] );
}
breal;
}
default : {
// turn off everything except thumbnail
if( 'thumbnail' !== $value ){
unset( $sizes[$key] );
}
break;
}
}
}
return $sizes;
}
Removing Image Sizes
Of course in some cases you don’t need so many image files. For example this website don’t even use a single one!
So, how to remove them?
First of all you can set to 0 all the image sizes in settings, like this:

Or you can use intermediate_image_sizes
filter hook. Or remove_image_size()
function inside after_setup_theme
hook, just like the way we registered them.
add_filter( 'intermediate_image_sizes', 'misha_turn_off_default_sizes' );
function misha_turn_off_default_sizes( $sizes ) {
unset( $sizes[ 'thumbnail' ] );
unset( $sizes[ 'medium' ] );
unset( $sizes[ 'large' ] );
unset( $sizes[ 'medium_large' ] ); // remove medium_large image size
unset( $sizes[ '1536x1536' ] ); // remove 1536x1536 image size
unset( $sizes[ '2048x2048' ] ); // remove 2048x2048 image size
return $sizes;
}
For images with -scaled
suffix the approach is a little bit different.
// remove -scaled image sizes
add_filter( 'big_image_size_threshold', '__return_false' );

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
This looks like pretty much exactly what I need, but I was wondering about the hook. Why does this go on
intermediate_image_sizes()
and not onintermediate_image_sizes_advanced()
? I’ve seen a couple of different suggested solutions for this problem and don’t know why some use one hook and some the other.Hi Sallie,
good question. And let me give you a good answer :)
intermediate_image_sizes
applies beforeintermediate_image_sizes_advanced
and passes only one parameter — the array of image sizes names, for example:array('thumbnail', 'medium', 'large', 'custom_size')
.So we can unset any of image sizes on the early step:
If you unset image sizes in
intermediate_image_sizes
(but not inintermediate_image_sizes_advanced
), it could improve website performance for a little because it prevents some actions in the code, I suppose.intermediate_image_sizes_advanced
runs after the image sizes names are converted into an associative array. You can use this filter the same way to unset image sizes by name, but you can use additional values that are passed to the filter.Thanks so much for the detailed explanation. I noticed when I added your code to my `functions.php` file, I got a “headers already sent” error in my Debug Bar.
What code do you mean? And what headers? I need more info :)
Misha, this is brilliant! Thank you so much.
In my case, I was uploading small graphics that are already the right size — ads and logos which have been prepped elsewhere. For that case, I wrote:
Hi, great article! I’m trying to catch animated gifs right before the images get created. Writing a plugin to catch that and generate the smaller animated gifs in order to keep the animation. I got most of the code sorted (I think) but can’t find the right hook…
image_make_intermediate_size is right after the images get resized…
Any guidance?
Hi Misha, i think there are some exceptions in the code you provide. Perhaps it depends on my theme, or WordPress changed, but i am not sure (Working on WordPress 5.2). I verified what files are produced in wp_content/uploads and these are my conclusions:
1. the filter
intermediate_image_sizes_advanced
is working, but theintermediate_image_sizes
is not working.2. the filter is working only for the default WordPress sizes (thumbnail, medium, medium_large, large). Custom theme sizes, and plugin sizes ignore the “unset”.
3. The array
get_intermediate_image_sizes()
outputs all the 4 WordPress default sizes, even if they are really unset. And proved there are no image produced in filesystem. I wonder why.4. To unset plugin sizes i used another action, and the function remove_image_size(). More details in Codex (https://codex.wordpress.org/Function_Reference/remove_image_size + https://developer.wordpress.org/reference/functions/remove_image_size/).