Registering Custom Image Sizes with add_image_size
add_image_size() tells WordPress to generate one more file per upload. The crop argument decides its shape, the hook decides whether it exists in time, and every size costs disk forever.
Some links on this page are affiliate links: if you buy through one, we may earn a commission at no extra cost to you. It does not change what we recommend; see the editorial policy.
add_image_size() adds one more file to every future upload — that is all it does. The size exists for templates and for srcset; it does not appear in the editor unless you also filter image_size_names_choose, and it does not exist for images uploaded before it was registered. Decide the crop deliberately, register it on the right hook and remember that each size costs disk on every upload from now on.
Signature
add_image_size( string $name, int $width = 0, int $height = 0, bool|array $crop = false );
| Argument | Meaning |
|---|---|
$name |
Size slug used everywhere else; prefix it to avoid clashes |
$width |
Maximum width in pixels; 0 means unconstrained |
$height |
Maximum height in pixels; 0 means unconstrained |
$crop |
false soft crop, true hard crop from centre, or array( x, y ) |
Register it on the right hook
<?php
add_action( 'after_setup_theme', 'ti_image_sizes' );
function ti_image_sizes() {
add_image_size( 'ti-card', 600, 400, true );
add_image_size( 'ti-wide', 1600, 0 );
}
In a theme, use after_setup_theme; in a plugin, init works. The size must be registered before any upload is processed — registering it inside a template or on wp is too late for the media upload request. ti-wide constrains only the width, which suits full-width images of any ratio.
Soft crop, hard crop and crop position
- Soft (
false) — scales to fit inside the box. A 3000 × 2000 upload in a 600 × 400 soft size becomes 600 × 400; a 3000 × 1500 upload becomes 600 × 300. Good for content images where nothing may be cut. - Hard (
true) — fills the exact box and trims the overflow from the centre. Good for card grids that need identical heights. - Positioned —
array( 'center', 'top' )keeps the top of the image, which suits portraits where centre-cropping cuts off heads. The x value isleft,centerorright; y istop,centerorbottom.
A size labelled 600 × 400 that soft-crops a portrait to 267 × 400 is the source of many "wrong size" reports; the visual side is in blurry images in WordPress.
Using the size
<?php
// Featured image in a card template.
the_post_thumbnail( 'ti-card' );
// Any attachment, with srcset and sizes added by core.
echo wp_get_attachment_image( $attachment_id, 'ti-card' );
Prefer these over building <img> tags from wp_get_attachment_image_src(): core adds srcset, sizes, width, height and the lazy-loading attributes only to markup it generates. Images of the same ratio but different widths share a srcset, so a hard-cropped 600 × 400 and 1200 × 800 pair gives high-density screens a sharp version for free.
Sizes and srcset
srcset only groups sizes with the same aspect ratio as the image being output. That has two practical consequences:
- A hard-cropped size has its own family. A 600 × 400 card is grouped with other 3:2 files only, so register a 1200 × 800 companion if cards must be sharp on high-density screens.
- A soft-cropped size joins the original's family, because it keeps the upload's ratio, and gets the full range of core sizes in its
srcsetfor free.
The sizes attribute core adds assumes the image may be as wide as its file (since WordPress 6.7, lazy-loaded images also get sizes="auto", which modern browsers resolve from the rendered width). For card grids, filter wp_calculate_image_sizes or pass a sizes attribute so phones do not download the 1200-pixel companion for a 300-pixel card.
Check what is registered
<?php
print_r( wp_get_registered_image_subsizes() );
Or run wp media image-size with WP-CLI. The list includes core, theme, WooCommerce and plugin sizes — the defaults are described in WordPress image sizes.
Removing sizes
A size can be removed only after it has been added, so the hook depends on who added it. For a parent-theme size, use after_setup_theme at a later priority:
<?php
add_action( 'after_setup_theme', function () {
remove_image_size( 'parent-theme-slider' );
}, 20 );
Plugins usually register sizes on init, which runs after after_setup_theme — WooCommerce does — so for a plugin size use init at a priority after the plugin's, such as add_action( 'init', …, 99 ).
To stop core generating the two largest hidden sizes, filter the list used during upload:
<?php
add_filter( 'intermediate_image_sizes_advanced', function ( $sizes ) {
unset( $sizes['1536x1536'], $sizes['2048x2048'] );
return $sizes;
} );
Removing the large hidden sizes saves disk but means high-density screens get nothing larger than large, and wide images look soft on them. Do it in a child theme or a small plugin so a theme update does not undo it. Existing files remain until you regenerate thumbnails with deletion enabled.
Every size is a cost
Each registered size multiplies the files per upload, the disk used and the work an optimizer does — compression plugins count every size against their quota. Before adding a size, check whether medium_large, large or an existing theme size already fits. If you do add sizes to an existing library, regenerate and then run your optimizer's bulk pass so the new files are compressed too; tools such as Imagify let you choose which registered sizes are optimised in their settings, so enable the new size there before the bulk pass.
Common mistakes
- Registering on a late hook, so uploads never get the size.
- Expecting the size in the editor without
image_size_names_choose. - Unprefixed names like
cardthat collide with a plugin's size. - Hard-cropping content images, cutting off parts readers need to see.
- Building
<img>by hand and losingsrcset, dimensions and lazy loading.
Verify
- Upload an image larger than the size and look for
-600x400.jpgin the uploads folder. - Output the size in a template and inspect the
img:srcsetandwidth/heightshould be present. - Run
wp media image-sizeand confirm removed sizes are gone from the list.
Frequently asked
- Either the upload is smaller than the size — WordPress never enlarges — or the size was registered after the upload. Sizes apply to new uploads only; regenerate thumbnails for existing images.
- Soft crop (crop false) scales the image to fit inside the width and height, keeping the ratio. Hard crop (crop true) fills the exact dimensions and cuts off whatever does not fit.
- Call remove_image_size( 'name' ) on a hook that runs after the size was added: after_setup_theme at priority 20 for a parent-theme size, init at a late priority such as 99 for a plugin size. Existing files stay on disk until you regenerate with deletion.