Images are usually the heaviest part of a WordPress page, and the most common cause of a slow Largest Contentful Paint (LCP). Optimizing them means four things: the right dimensions, the right format, good compression, and smart loading. Most of it can be automated on your server.
1. Upload sensible dimensions
A 6000-pixel photo straight from a camera is useless on a 1200-pixel-wide content column.
- WordPress (5.3+) automatically scales down uploads larger than 2560 pixels (the “big image threshold”). You can lower it:
// in a small plugin or the theme's functions.php
add_filter( 'big_image_size_threshold', fn() => 1920 );
- WordPress generates several sizes (thumbnail, medium, medium_large, large, plus theme sizes) and outputs
srcsetandsizes, so browsers download the smallest suitable file. Make sure your theme useswp_get_attachment_image()or the block editor, so this works. - Remove image sizes you never use (themes and plugins add many), to save disk space and processing time.
2. Use modern formats: WebP and AVIF
| Format | Typical size vs JPEG | Browser support |
|---|---|---|
| JPEG/PNG | baseline | universal |
| WebP | 25–35% smaller | all modern browsers |
| AVIF | 40–50% smaller | all modern browsers (slower to encode) |
- WordPress core supports uploading WebP and AVIF (AVIF since 6.5), if your server’s image library supports them.
- Check your server: Tools → Site Health → Info → Media Handling shows whether ImageMagick or GD can write WebP and AVIF. Install
php-imagickwith a recent ImageMagick if needed. See PHP extensions. - Core can generate WebP sub-sizes for JPEG uploads with the
image_editor_output_formatfilter:
add_filter( 'image_editor_output_format', function ( $formats ) {
$formats['image/jpeg'] = 'image/webp';
return $formats;
} );
3. Compress
- Plugins: ShortPixel, Imagify, EWWW Image Optimizer, Optimole, and others compress images, convert them to WebP/AVIF, and can bulk-optimize your existing library. Some process images on their servers (using your quota), and some locally on your VPS.
- Local tools on your VPS (free, no quotas):
sudo apt install -y jpegoptim optipng webp
# lossy JPEG to quality 82, strip metadata
find /var/www/example.com/wp-content/uploads -name '*.jpg' -size +200k -exec jpegoptim --max=82 --strip-all {} \;
# make WebP copies
find /var/www/example.com/wp-content/uploads -name '*.jpg' -exec sh -c 'cwebp -q 80 "$1" -o "${1%.*}.webp"' _ {} \;
Back up the uploads folder before bulk changes. See backup strategy.
Serving the .webp copies: a plugin can rewrite URLs, or Nginx can serve WebP automatically when the browser accepts it:
map $http_accept $webp_suffix {
default "";
"~*webp" ".webp";
}
location ~* ^/wp-content/uploads/.+\.(png|jpe?g)$ {
add_header Vary Accept;
try_files $uri$webp_suffix $uri =404;
expires 30d;
}
(This expects WebP files named image.jpg.webp. Adjust it to match your naming.)
4. Load images smartly
- Lazy-load below-the-fold images. WordPress adds
loading="lazy"automatically. See WordPress lazy loading. - Don’t lazy-load the LCP image (usually the hero or featured image). WordPress tries to skip the first content image, and adds
fetchpriority="high". Check with PageSpeed Insights. - Always output
widthandheightattributes (WordPress does), so the layout doesn’t shift (CLS).
5. Deliver from a CDN
A CDN serves images from servers near visitors. Some image CDNs (Cloudflare Images, BunnyCDN Optimizer, Optimole) also resize and convert on the fly. See WordPress CDN setup.
6. Cache headers
Images don’t change once uploaded, so cache them for a long time:
location ~* \.(jpg|jpeg|png|gif|webp|avif|svg)$ {
expires 30d;
access_log off;
}
See Nginx static file caching.
Measure
- PageSpeed Insights / Lighthouse: “Properly size images”, “Serve images in next-gen formats”, “Largest Contentful Paint element”.
- Before and after: check total page weight in your browser’s DevTools (Network tab, filter by Img).
See Core Web Vitals and server performance.
Quick reference
| Goal | How |
|---|---|
| Smaller dimensions | big_image_size_threshold, responsive srcset |
| Modern formats | WebP/AVIF via Imagick, plugin, or cwebp |
| Compression | ShortPixel/Imagify/EWWW, or jpegoptim |
| Loading | lazy-load below the fold; fetchpriority="high" for LCP |
| Delivery | CDN + long cache headers |
Related: WordPress performance tuning and WordPress VPS hosting.