Skip to content
WordPress

How to Serve Properly Sized Images in WordPress

· · 10 min read
How to Serve Properly Sized Images in WordPress

A 4000-pixel-wide photo displayed in a 400-pixel content column is not a formatting choice, it is a page speed problem you are shipping to every visitor. WordPress has decent built-in tooling for this, srcset generation, lazy loading, multiple registered image sizes, but the defaults only get you partway, and most sites are still serving images far larger than any layout actually needs. This covers what WordPress already handles automatically, what you still need to configure yourself, and how to verify the fix actually worked rather than assuming a plugin’s activation screen means the job is done.

What WordPress Already Does For You

Since WordPress 4.4, every image uploaded through the media library automatically generates several sizes: thumbnail, medium, medium_large, and large, alongside the original full-size upload. The block editor and most themes use the `srcset` and `sizes` attributes to let the browser pick the most appropriate size for the visitor’s actual screen, rather than always serving the largest version.

This built-in behavior solves the most extreme version of the problem, a phone will not download the full 4000px original just because that is what got uploaded, but it does not solve everything. Default WordPress image sizes are generic, not tuned to your specific theme’s actual content width, and a poorly designed theme or a manually inserted image can bypass responsive sizing entirely.

Step 1: Upload at a Sensible Size in the First Place

The single highest-leverage fix is upstream of any plugin: resize images before uploading rather than relying entirely on WordPress or a plugin to compensate after the fact. If your content column is 800px wide, uploading a 4000px photo means WordPress is generating and storing five oversized variants instead of appropriately sized ones, and the original 4000px file still sits on your server consuming disk space and, in some configurations, still getting served.

A reasonable target for most blog and content images: 1200 to 1600px on the longest edge covers retina displays at typical content widths without going dramatically further than necessary. Full-bleed hero images that span the entire browser width are the exception and may genuinely need something closer to 1920 or 2560px.

Step 2: Pick and Configure an Optimization Plugin

Three plugins come up repeatedly, and they are not interchangeable in approach.

Smush compresses images automatically on upload and offers bulk optimization for your existing media library. Its free tier covers basic lossy and lossless compression; the paid tier adds WebP conversion and larger file size limits.

ShortPixel offers both lossy and lossless compression with a credit-based free tier (a limited number of images per month), and includes WebP and AVIF conversion, which produce meaningfully smaller files than JPEG or PNG at comparable visual quality.

Imagify, from the WP Rocket team, follows a similar credit-based free tier structure with adjustable compression levels, letting you choose more aggressive compression for a smaller file size versus more conservative compression that preserves more visual fidelity.

Installation and setup for any of these follows the same basic pattern: install and activate through Plugins > Add New, connect an API key if the plugin requires one (ShortPixel and Imagify both do, Smush’s core features do not), then run the bulk optimizer against your existing media library rather than only optimizing new uploads going forward.

Step 3: Confirm Lazy Loading Is Actually Active

WordPress has included native lazy loading (adding `loading=”lazy”` to image tags automatically) since version 5.5. In most cases this needs no configuration at all. It is worth verifying rather than assuming, though, since some themes or older plugins occasionally disable it, or a caching plugin’s HTML minification can strip the attribute if misconfigured.

Check by viewing page source (not the browser inspector, the actual delivered HTML) and searching for `loading=”lazy”` on images below the visible fold. If it is missing, a plugin like a3 Lazy Load can reintroduce the behavior, though first check why native lazy loading is not already working, since adding a second lazy-load system on top of a broken native one sometimes causes more problems than it solves.

Step 4: Use the Block Editor’s Own Image Sizing Controls

When adding an Image block in the block editor, the block’s own settings panel lets you select which registered image size to insert (Thumbnail, Medium, Large, or Full Size) rather than always inserting the full original. Choosing an appropriately sized registered variant here, rather than defaulting to Full Size out of habit, directly controls what gets served without needing any plugin at all.

This is a frequently overlooked control. It is common to see full-size, unnecessarily large images embedded in body content specifically because whoever wrote the post never changed the dropdown away from its default selection.

Step 5: Add Alt Text and Descriptive File Names While You Are In There

Image optimization and accessibility are separate concerns, but they get handled in the same workflow often enough to mention together. Every image should have alt text describing its content for screen reader users, and this also gives search engines context about the image that a filename like IMG_4821.jpg never will. Rename files to something descriptive before upload, and fill in the alt text field in the media library rather than leaving it blank.

Step 6: Consider a CDN for Sites With Meaningful Traffic

A Content Delivery Network distributes your images across servers geographically closer to your visitors, reducing latency compared to every visitor pulling images from a single origin server. Many CDN services also apply their own on-the-fly image optimization and format conversion, serving WebP to browsers that support it and JPEG as a fallback, without you needing to manage multiple file formats manually in your media library.

For a small site with modest traffic, a CDN is a nice-to-have rather than urgent. For a site pulling meaningful traffic from geographically spread-out visitors, or one with a large, image-heavy media library, the latency and bandwidth savings become significant enough to justify the setup.

Step 7: Convert to Modern Formats

WebP produces noticeably smaller file sizes than JPEG at comparable visual quality, and AVIF goes further still, though AVIF encoding is more computationally expensive and its browser support, while now broad, still trails WebP slightly. Most of the optimization plugins mentioned above handle this conversion automatically as part of their optimization pipeline, including serving the original format as a fallback for the rare older browser that does not support the newer format.

Manual conversion is possible but rarely worth the effort compared to letting a plugin handle format negotiation automatically per visitor’s browser capabilities.

Auditing What Is Actually Happening on Your Site

Configuration settings that look correct in a plugin’s dashboard do not guarantee the front end is actually serving optimized images. Run your homepage and two or three representative content pages through Google PageSpeed Insights or GTmetrix and check specifically for “Properly size images” and “Serve images in next-gen formats” flags in the report. If these still show up as opportunities after you believe you have fixed the problem, something in the pipeline, a theme overriding default sizes, a plugin conflict, cached old versions of images, is not actually working as configured.

Browser dev tools’ Network tab, filtered to Img requests, shows the actual transferred file size for every image on the page as it loads. Comparing that against the image’s rendered display size (right-click, Inspect, check the computed width and height) tells you directly whether an oversized image is being served for a smaller display area, which is the exact problem this whole guide addresses.

Common Mistakes

Running bulk optimization once and never revisiting it. New images get added to a site continuously; optimization needs to be an ongoing, ideally automatic-on-upload process, not a one-time cleanup task.

Over-compressing to the point of visible quality loss, particularly on hero images and product photography where visual fidelity genuinely matters to the page’s purpose. Test compression settings visually on a few representative images before applying an aggressive setting site-wide.

Assuming a CDN alone solves image sizing. A CDN speeds up delivery of whatever file you give it; it does not automatically fix a 4000px image being embedded where a 400px version would suffice, unless the specific CDN service includes its own resizing logic, which not all of them do by default.

Ignoring the original full-size file. Some optimization plugins optimize the generated thumbnail sizes but leave the original full-resolution upload untouched and, depending on theme and plugin configuration, still reachable and occasionally still served in specific contexts like a lightbox gallery plugin that defaults to the full-size original.

Registering Custom Image Sizes for Developers

WordPress’s default sizes (thumbnail, medium, medium_large, large) are generic and rarely match a specific theme’s actual layout widths exactly. If you are building or customizing a theme, registering custom sizes tuned to your real content widths gives visitors a closer match between what gets generated and what actually gets displayed, rather than relying on the browser to pick the nearest oversized default.

function my_theme_image_sizes() {
    add_image_size( 'blog-thumb', 400, 300, true );
    add_image_size( 'hero-banner', 1920, 800, true );
}
add_action( 'after_setup_theme', 'my_theme_image_sizes' );

The third parameter (`true` in both examples above) controls hard cropping to the exact dimensions versus proportional scaling. Use hard cropping for consistent grid layouts where every image needs identical dimensions, like a blog archive grid, and proportional scaling for content where preserving the original aspect ratio matters more than uniform sizing.

One catch worth knowing: registering a new image size only affects images uploaded after the change. Existing media library images will not have the new size generated automatically. A plugin like Regenerate Thumbnails runs the generation process retroactively across your existing library, which is necessary any time you add, remove, or change a registered image size on a site with existing content.

Image Sizing for WooCommerce Product Galleries

Stores running WooCommerce have an additional layer of size settings specifically for product images, configured under WooCommerce > Settings > Products > Display. These control the catalog image size (shown in shop grids), the single product image size (shown on the individual product page), and thumbnail size for the gallery strip beneath the main product image.

A common performance problem on WooCommerce stores specifically: catalog pages showing dozens of products at once, each pulling a larger-than-necessary image because the catalog image size setting was left at an overly generous default. Since a catalog grid page loads many images simultaneously rather than one at a time, oversizing here compounds fast, a few unnecessary extra kilobytes per product image multiplied across forty products on a single archive page adds up to a meaningfully slower page load than the same mistake on a single blog post.

How Retina and High-DPI Screens Complicate This

A “properly sized” image is not a single fixed number, it depends on the visitor’s screen pixel density too. A retina or other high-DPI display renders at roughly double the effective pixel density of a standard screen, meaning an image that looks perfectly sharp at exactly its display width on a standard monitor will look visibly soft on a retina display unless it is served at roughly twice the pixel dimensions.

This is exactly what `srcset` and `sizes` attributes solve, offering the browser multiple resolution options and letting it choose based on both the visitor’s viewport size and their screen’s pixel density, rather than a single one-size-fits-all image. The practical implication for your own upload sizing: the “sensible size” guidance from Step 1 already accounts for this, a 1200 to 1600px upload for an 800px display column is intentionally oversized relative to standard displays specifically to cover retina density without needing separate 1x and 2x files managed manually.

Checking Whether Your Theme Is Actually Using srcset Correctly

Not every theme implements responsive images correctly, particularly older or heavily customized themes where a developer hardcoded an `<img>` tag directly in a template file rather than using WordPress’s built-in `wp_get_attachment_image()` function, which handles srcset generation automatically.

Inspect a hardcoded image element in your browser’s dev tools. If it has only a single `src` attribute and no `srcset` at all, that specific image is not getting responsive size negotiation, regardless of how well-optimized the underlying file is. This is a template-level fix, not something an optimization plugin can retroactively add, since the plugin has no control over markup a theme is generating directly rather than through WordPress’s standard image functions.

A Realistic Before-and-After Example

To make the abstract concrete: a typical unoptimized blog featured image straight from a modern phone camera commonly lands somewhere around 3-6MB at 4000+ pixels wide. Resized to 1600px and run through a compression plugin at a reasonable quality setting, the same image typically drops to somewhere in the 150-400KB range depending on content complexity (a busy, detailed photo compresses less efficiently than a simple graphic or screenshot). Converted to WebP on top of that, expect a further meaningful reduction again, often another 25-35% smaller than the equivalent optimized JPEG at comparable visual quality.

Multiply that difference across every image on a page, and across every page a visitor loads in a session, and the cumulative effect on both load time and the visitor’s own mobile data usage is substantial, not a marginal, ignorable optimization.

Frequently Asked Questions

Do I need a plugin, or does WordPress handle image optimization on its own?
WordPress core generates multiple sizes and applies srcset automatically, which covers responsive delivery. It does not apply compression or format conversion beyond what your uploaded file already has, which is where a dedicated optimization plugin adds real value.

Will optimizing images hurt visual quality?
At reasonable compression settings, the difference is imperceptible to most visitors in normal browsing conditions. Extremely aggressive compression settings can introduce visible artifacting, particularly on images with fine detail or gradients, so preview results before applying a setting across your entire library.

What is the difference between lazy loading and image compression?
Lazy loading delays when an image downloads (only as it approaches the visible viewport), which speeds up initial page load without changing file size at all. Compression reduces the actual file size of the image itself. Both matter and address different parts of the same overall performance problem.

Should I delete the original full-size upload after optimizing?
Generally no, since WordPress and various plugins may reference it in ways that are not always obvious (certain gallery or lightbox plugins default to the original), and deleting it removes your ability to regenerate other sizes later if you change theme or need a larger variant. Optimize it rather than deleting it.