Monday, 9:12 AM. The homepage looked fine in staging, but real users were bouncing before the hero section finished painting. No outage. No 500s. Just a quiet conversion leak.
In PageSpeed Insights, the culprit was obvious: Largest Contentful Paint (LCP) had drifted beyond 3 seconds on mobile. The biggest element was the hero image, and we had created a perfect storm: oversized originals, inconsistent srcset, and stale caches serving old derivatives.
This article is a practical WordPress image optimization runbook you can execute without gambling on fragile one-click plugin magic. The goal is not “perfect Lighthouse.” The goal is stable, repeatable gains with clear rollback paths.
If you want companion context, these earlier 7tech posts are useful in parallel: Speculation Rules + Early Hints for faster LCP, pipeline hardening for safer deploys, hybrid stack hardening, and WordPress cron reliability.
The bottleneck is usually not one thing
A common mistake is compressing one image and expecting LCP to magically recover. Google’s LCP guidance is blunt: you need to optimize the whole chain, from server response to resource priority to render timing. In practice, your image work should answer four questions:
- Is the hero candidate discoverable early in HTML?
- Is the file format and size right for the viewport?
- Is
srcset/sizeshelping, not fighting, the browser? - Did cache and derivatives update predictably after changes?
Tradeoff to remember: aggressive compression can reduce bytes but introduce visible artifacts. You are optimizing for user perception and speed, not just tiny files.
Runbook step 1, audit image reality before changing anything
Do a quick inventory from WP-CLI. You need to know what you are serving today: mime types, dimensions, and suspiciously heavy files.
# Run inside your WordPress root
wp db query "
SELECT p.ID,
p.post_title,
pm_mime.meta_value AS mime_type,
pm_file.meta_value AS file_path
FROM wp_posts p
LEFT JOIN wp_postmeta pm_mime ON pm_mime.post_id = p.ID AND pm_mime.meta_key = '_wp_attachment_metadata'
LEFT JOIN wp_postmeta pm_file ON pm_file.post_id = p.ID AND pm_file.meta_key = '_wp_attached_file'
WHERE p.post_type = 'attachment'
AND p.post_mime_type LIKE 'image/%'
ORDER BY p.ID DESC
LIMIT 30;
" --skip-column-names
# Spot attachments above 500 KB directly in uploads
find wp-content/uploads -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" -o -name "*.webp" -o -name "*.avif" \) \
-size +500k -print | head -n 50
Why this matters: the heaviest file is not always the LCP element, but this audit quickly reveals patterns, especially old PNG heroes and oversized JPEGs copied from design exports.
Runbook step 2, adopt AVIF carefully, not blindly
WordPress 6.5 introduced AVIF support in core, but the docs are clear about a key dependency: your host image stack (Imagick/LibGD) must support AVIF. Check Site Health first. If support is missing, do not force the rollout.
When AVIF is available, start with hero and above-the-fold editorial images. Keep fallback behavior through normal responsive markup and avoid format-only dogma. AVIF is often smaller than JPEG and WebP at similar quality, but encoded quality settings still need tuning by content type.
<?php
/**
* MU-plugin example: tune AVIF output quality and convert JPEG derivatives to AVIF.
* Test on staging first, then rollout gradually.
*/
add_filter('wp_editor_set_quality', function ($quality, $mime_type) {
if ($mime_type === 'image/avif') {
return 72; // Start conservative, review visual artifacts in dark gradients.
}
return $quality;
}, 10, 2);
add_filter('image_editor_output_format', function ($formats) {
// Keep originals, generate AVIF derivatives where supported.
$formats['image/jpeg'] = 'image/avif';
return $formats;
});
Tradeoff: converting every JPEG derivative to AVIF can increase CPU on upload/regeneration. On smaller VPS setups, batch these jobs during low-traffic windows.
Runbook step 3, fix srcset hygiene and image intent
WordPress automatically adds responsive attributes, but “automatic” does not mean “correct for every theme.” The default sizes can mismatch your layout width rules, causing browsers to fetch larger assets than needed.
Review your hero templates and block patterns. If your content column is 860px, but your sizes implies near-full viewport on desktop, you are paying for pixels nobody sees.
Also remember SEO and discoverability constraints from Google’s image guidance:
- Use real
<img>/<picture>markup, not CSS-only hero backgrounds for critical discoverable images. - Keep meaningful
alttext and descriptive filenames, without keyword stuffing. - Use representative
og:imagewhere social previews matter.
Runbook step 4, regenerate thumbnails with cache-safe sequencing
After changing image format filters or size rules, regenerate derivatives in a controlled order. This is where many teams break pages by clearing CDN cache too early.
set -euo pipefail
# 1) Put site in maintenance mode only if you expect visible media churn.
wp maintenance-mode activate
# 2) Backup DB before large media operations.
wp db export /tmp/pre-image-regeneration-$(date +%F).sql
# 3) Regenerate only missing first, then evaluate.
wp media regenerate --only-missing --yes
# 4) If layout rules changed significantly, full regeneration in off-peak window.
# wp media regenerate --yes
# 5) Purge page/object/CDN caches after derivatives exist.
# (Use your cache plugin/edge provider command here)
# 6) Turn maintenance off and verify key URLs.
wp maintenance-mode deactivate
Tradeoff: full regeneration gives consistency, but can be I/O heavy and slow on shared disks. Prefer incremental regeneration unless you changed global image sizing behavior.
What “done” looks like in production
- LCP improves in field data (CrUX/RUM), not only lab tests.
- Hero images ship in appropriate formats and dimensions for common breakpoints.
- No spike in broken thumbnails or 404s after cache purge.
- Editorial team has a simple upload standard: target dimensions, file-size caps, and naming rules.
If you automate releases, connect image checks to CI gates the same way we enforce safer deploy policy in our GitHub Actions hardening workflow.
Troubleshooting, when speed gains do not appear
1) LCP is still high even after AVIF rollout
Check resource discovery and priority first. If the hero image URL is injected late via JavaScript, compression alone will not solve render delay.
2) AVIF upload fails in WordPress
Your server image libraries may not support AVIF. Confirm support in Site Health under Media Handling. If unsupported, keep WebP/JPEG path until host stack is upgraded.
3) Regeneration succeeded, but old images still load
Usually cache ordering. Ensure derivative generation completed before CDN or full-page cache purge. Also verify no hardcoded legacy file paths inside theme templates.
4) Image quality complaints after optimization
Raise quality for specific mime types or critical image classes. A global low setting may save bytes but harm product screenshots or charts where clarity matters.
FAQ
Should I convert everything to AVIF right away?
Not automatically. Start with templates where LCP matters most, verify host support, then expand. Broad conversion without validation can increase CPU load and operational risk.
Is WebP obsolete now that AVIF exists?
No. AVIF is often more efficient, but WebP remains broadly supported and operationally simpler in some stacks. Choose based on your traffic mix, tooling, and reliability goals.
How often should I regenerate thumbnails?
Only when format/sizing logic changes or when repairing missing derivatives. Running full regeneration routinely without need just burns resources.
Actionable takeaways
- Run a WP-CLI media audit before touching settings.
- Adopt AVIF gradually, gated by real host capability checks.
- Treat
srcset/sizesas layout contracts, not defaults to ignore. - Sequence regenerate then cache purge, never the other way around.
- Measure success in field LCP and conversion behavior, not just synthetic scores.
If your site has already implemented release safety and cron reliability, this runbook is the missing middle layer, making WordPress image performance predictable instead of seasonal firefighting.

Leave a Reply