WordPress images: what core does and what you must do
WordPress resizes, lazy-loads and prioritizes images for you, up to a point. What core does on its own, where it stops, and how to get the main image right.
In this guide
What core does for every image
These behaviors come from the WordPress core source. The first group happens when you upload a file, and the second when a page is printed.
On upload
- Smaller copies. WordPress makes several sizes. Its settings default to a thumbnail of 150 pixels (cropped), a medium size of 300, a medium-large size of 768 and a large size of 1,024. Themes and plugins can add more.
- A limit on huge originals. Images wider or taller than 2,560 pixels are scaled down by default, and the larger original is kept. A plugin or theme can change the limit with the
big_image_size_thresholdfilter. - Metadata removal. The
image_strip_metasetting defaults to true, so resized copies drop embedded metadata. - Formats. WordPress accepts WebP and AVIF files. Whether it can create resized copies of them depends on the image library on your server. The
image_editor_output_formatfilter lets a plugin choose the output format for the copies. By default, only phone formats such as HEIC are converted, to JPEG.
When a page is printed
- `srcset` and `sizes`. WordPress lists the copies in
srcset, so the browser can choose. The defaultsizesit writes is(max-width: Wpx) 100vw, Wpx, where W is the width of the size used. That says "this image takes the full width of the window until the window is as wide as the image". It is a good guess for an image that fills the content area, and a poor one for an image in a narrow column or a grid. See srcset and sizes. - `sizes="auto"`. Since version 6.7, a lazy-loaded image that has a
widthattribute and asizesvalue getsauto,added in front of it. MDN explains thatautotells the browser to choose the image from the expected layout width of the element, and to fall back to the other values if it cannot. MDN's compatibility data lists Chrome 126, Firefox 150 and Safari 27 (partial) for it. A browser that does not knowautouses the rest of the list. - `width` and `height`. WordPress adds them, so the browser can reserve space and avoid layout shifts. See image width and height.
- `loading="lazy"` and `decoding="async"`. Images and iframes are lazy-loaded by default. The first three images in the content are left alone, because the threshold
wp_omit_loading_attr_thresholddefaults to 3 since version 6.3. - `fetchpriority="high"`. The first image in the content that is large enough, at least 50,000 square pixels with its width and height set, gets this attribute, which tells the browser to fetch it early.
This is a good start, and for a typical blog post it is often enough. The trouble is in the pages that do not look like a typical blog post.
Where core stops
- The file you upload. WordPress does not know that a 2,400-pixel photograph is far larger than the 700-pixel slot it will fill. The scaled copies help, but the choice of size is still made by the theme or the block.
- Images outside the post content. A hero image written into a theme template, a slider, a background set in CSS, a logo in a header and an image inside a page builder widget may not get the same treatment. A background image set in CSS gets no
srcset, no lazy loading and no priority. - The wrong size choice. If the editor inserts the "full" size into a small space, the browser may download the full file. If the default
sizesvalue does not describe a column layout, it may pick one that is too large. - Page builders and plugins that rewrite images. Some lazy-load everything, including the main image, or replace
imgtags with their own markup. - Compression. Core's quality settings are fixed defaults. A photograph exported at maximum quality is still large, even if WordPress makes smaller copies of it.
Step 1: find the main image
The largest image above the fold is usually the Largest Contentful Paint element. Run the free audit or PageSpeed Insights and open LCP request discovery and LCP breakdown. Note what the element is. Then check:
- Is it lazy-loaded? View the page source and find the image. If it has
loading="lazy", remove it. A lazy-loaded main image waits to be discovered late. See lazy loading. - Does it have `fetchpriority="high"`? If not, and it is an
imgelement, add it. Core adds it to images that it prints or filters itself, such as ones in post content, but a plainimgtag in a theme file or a builder widget may not get it. - Is it the right size? Compare the file's dimensions with the size it is shown at on a phone and on a desktop screen. If the file is much larger, upload or select a smaller one.
- Is it a CSS background? If so, the browser finds it late and cannot use
srcset. Consider animgelement instead. See how to fix a slow LCP.
Step 2: upload better files
The best fix is the cheapest. Before you upload:
- Resize to the largest size the layout needs. For a content column of 700 to 800 pixels on desktop, a file of 1,400 pixels wide covers screens with twice the pixel density. Files much wider than that add weight and no sharpness.
- Choose a format. JPEG for photographs, PNG for graphics that need transparency or sharp edges, WebP or AVIF for smaller files. See WebP and AVIF.
- Compress. A browser tool such as Squoosh lets you compare quality and size side by side.
- Name and describe the file for people who use screen readers and for search. This does not change speed, but it is the time to do it.
If you have a large library of old images, do not redo all of them. Start with the pages that get the most visits, and with the largest files in the Media Library.
Step 3: check how images are inserted
- Pick the size that fits. In the editor, an image can be inserted at several of the sizes WordPress made. Choose the smallest one that still looks sharp in its slot.
- Check images in columns and grids. If a column holds a quarter of the width, a
sizesvalue that says 100vw makes the browser download an image that is too big. Browsers that supportsizes="auto"avoid this for lazy-loaded images, and Chrome has done since version 126. For others, set a bettersizesvalue, which the theme or a developer can do with thewp_calculate_image_sizesfilter. - Check sliders and galleries. Many load every image at once. Make only the first slide load early, and let the others wait.
- Check the theme's own image sizes. If you change themes, old images may not have the sizes the new theme asks for. WordPress then uses the closest ones it has, which may be too large or too small. A regeneration tool, run once, makes the missing sizes.
Step 4: use a plugin or a CDN carefully
Plugins and image CDNs can convert images to WebP or AVIF, resize them for each device and serve them from a network close to the visitor. They can help a lot on a large library. Before you rely on one:
- Test that the main image is not lazy-loaded by the plugin.
- Test that the converted file is served only to browsers that can use it, and that the original still works.
- Check that the plugin does not add a second
srcseton top of WordPress's. - Keep the originals, in case you change tool.
The web.dev guide to image CDNs explains the idea, and our image optimization guide covers the formats and sizes.
Mistakes to avoid
- Lazy-loading the first image. It is the most common mistake, and it delays the largest paint.
- Uploading camera files. A 6,000-pixel photograph scaled to 2,560 pixels is still far too large for most slots.
- Using the full size everywhere. Pick the size that matches the layout.
- Trusting a score. A tool may report "properly sized" because it saw the scaled copy, not the best size. Check the real dimensions against the slot.
- Compressing twice. Squeezing an already compressed file and then letting a plugin squeeze it again can leave visible damage.
Check your own page
Run the free audit and open Improve image delivery, LCP request discovery and the list of the largest files. If the main image is lazy-loaded, much larger than its slot, or loaded late, fix it first. After that, work through the largest images in order.
Sources
- WordPress core source: media.php (
srcsetandsizes,sizes="auto", loading and priority attributes,big_image_size_threshold,image_strip_meta,image_editor_output_format) and schema.php (the default image sizes). - img element on MDN, with its compatibility data for
sizes="auto". - Image CDNs on web.dev.
- Squoosh, the browser image compression tool.
Start here
Free website audit
Live Google data for any public page: mobile and desktop.
Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it
Rather have this done for you? WordPress speed · Book a call