PageSpeed Matters
    Speed Audit
    Let's Talk
    PageSpeed Matters
    Book a Call
    WordPress Guide

    WordPress Image Optimization (2026)

    Matt SuffolettoWritten by Matt Suffoletto
    Published June 23, 2026 15 min read
    Share

    Images are still the single largest payload on most WordPress sites in 2026. The average page ships 1.8 to 2.4MB of images out of a 2.5 to 3.2MB total, and on content-heavy pages it is not unusual to see 5 to 8MB of images alone. Every one of those bytes shows up in Largest Contentful Paint, Total Blocking Time, and the data bill of every mobile visitor on a metered plan.

    The upside is that image work is the highest-impact performance change available on WordPress. Switching to WebP cuts file size by 25 to 35% with no visible quality loss. AVIF cuts another 20 to 30% on top. Combined with correct responsive sizing, lazy loading the off-screen images, and explicitly preloading the LCP image, a typical WordPress page drops 40 to 70% of its weight and 1 to 2 seconds of LCP without touching a line of theme code.

    This guide covers the format choice (WebP and AVIF on WordPress 5.8 and later), compression on upload, responsive srcset, lazy loading and the critical exception for the LCP image, preloading with fetchpriority, the plugin shortlist, and image CDN options. If you are still triaging which speed problem to fix first, start with why is WordPress so slow; for the full performance stack including hosting and caching, see the parent Ultimate Guide to WordPress Speed Optimization.

    TL;DR

    Pick one image plugin, do not stack two. ShortPixel or Imagify for most sites, EWWW for sites that need local processing without an API quota, Smush only if you already have a Smush Pro license. Enable WebP delivery and turn on AVIF if your plugin supports it (ShortPixel and Imagify do in 2026). Compress on upload at 75 to 82 quality, keep originals, and regenerate existing media library images once. Use the WordPress native `loading="lazy"` attribute on every image below the fold, and make sure the LCP image is NOT lazy loaded and HAS `fetchpriority="high"`. Add a `<link rel="preload" as="image">` for the hero image on landing pages. Serve through an image CDN (BunnyCDN Optimizer, Cloudflare Polish, ShortPixel Adaptive Images) so the format and size are negotiated per visitor. Expect 800ms to 1.8s of LCP improvement and a 40 to 60% reduction in page weight after a complete image overhaul.

    Key Takeaways

    • WebP cuts image size 25 to 35% with no visible quality loss; AVIF cuts another 20 to 30% on top.
    • WordPress has native WebP support since 5.8 and improved AVIF handling since 6.5.
    • Compress on upload at quality 75 to 82, and always keep the original for re-compression later.
    • Never lazy load the LCP image; set `fetchpriority="high"` on it instead.
    • Preload the LCP image with `<link rel="preload" as="image">` to remove the discovery delay.
    • Pick one image plugin: ShortPixel, Imagify, EWWW or Smush. Stacking two breaks delivery.
    • An image CDN negotiates format and size per visitor, so a Safari user gets JPEG XL or WebP without a plugin rule.

    WebP and AVIF on WordPress 5.8 and Later

    WebP and AVIF are the two modern image formats that matter in 2026. WebP, from Google, is supported in every major browser since 2020 and produces files 25 to 35% smaller than equivalent-quality JPEG. AVIF, based on the AV1 video codec, is supported in Chrome, Edge, Firefox, Safari 16.4 and later, and Opera, and produces files 20 to 30% smaller than WebP at matching quality.

    WordPress added native WebP upload support in version 5.8 (July 2021). You can drag a `.webp` file into the media library and it will be inserted into posts like any other image. Version 6.5 added the same level of support for AVIF, so a modern WordPress install can ingest, store and serve both formats directly.

    What WordPress core does not do automatically is convert your existing JPEG and PNG uploads to WebP or AVIF. For that, you need a plugin (covered in section 6) or a server module like Cloudflare Polish, BunnyCDN Optimizer, or the ImageMagick + WebP module built into many managed hosts. The plugin or module reads the original, generates one or more modern format copies, and serves the right one based on the browser's `Accept` header.

    A practical 2026 configuration: keep the original JPEG or PNG, generate a WebP version at quality 75 to 82, generate an AVIF version at quality 50 to 60 (AVIF's quality scale runs lower than JPEG), and let the plugin or CDN serve `.avif` to browsers that send `image/avif` in their Accept header, `.webp` to browsers that send `image/webp`, and the original to anything else. The fallback path is important: legacy clients (old email clients embedding images, some social media preview crawlers) still need the JPEG.

    Compression on Upload

    Compression is where most of the savings live. A typical 4000px DSLR JPEG from a stock photo site is 3 to 6MB at quality 95. The same image at quality 80 is 600 to 900KB and visually identical at the screen sizes WordPress will actually display. At quality 75 it is 400 to 600KB and still indistinguishable on a phone or laptop screen.

    The rule of thumb that works across every plugin in 2026: JPEG and WebP at quality 78 to 82, AVIF at quality 55 to 60, PNG only when transparency is required (otherwise convert to WebP or AVIF which both support transparency at smaller size). Configure your image plugin to compress on upload, not as a separate batch job, so the savings are baked in from the first time the file hits the server.

    Always keep the original. Every reputable plugin offers a 'keep originals' or 'backup originals' option that stores the unmodified file in a parallel directory. This matters for three reasons: you may want to re-compress at a different quality later; you may switch plugins; and the original is the source for new thumbnail sizes if your theme changes.

    For sites with an existing media library, run a one-time bulk optimization after installing the plugin. ShortPixel, Imagify and EWWW all expose a 'bulk optimize' screen that walks the entire media library and processes every image. Expect 5 to 60 minutes per 1,000 images depending on the plugin's processing model (local versus API). After the bulk run, total media disk usage typically drops 40 to 65%.

    Responsive srcset and sizes

    WordPress has generated responsive image markup automatically since version 4.4 (2015), and the implementation has matured to the point where you almost never need to override it. When you upload a 2000px wide image, WordPress generates thumbnail, medium, medium_large, large and full size variants, then outputs `<img>` markup with a `srcset` attribute listing all of them and a `sizes` attribute describing the layout.

    The browser reads `sizes`, calculates the actual display width, picks the smallest entry in `srcset` that is large enough for the visitor's screen density, and downloads only that one. A 320px wide phone gets the 300px thumbnail. A 4K monitor at full width gets the 2000px original.

    Two common things go wrong with srcset in 2026. First, the `sizes` attribute defaults to `(max-width: NNNpx) 100vw, NNNpx` based on the post's content width, which is wrong for theme layouts that use multi-column grids. The browser then downloads an image too large for its actual rendered size, wasting bandwidth. Fix it with the `wp_calculate_image_sizes` filter in `functions.php` or a child theme, returning the actual rendered width for each context. Modern block themes generally handle this correctly through the block markup.

    Second, themes that bypass `wp_get_attachment_image` and output raw `<img src>` tags lose srcset entirely. Audit your theme: any image rendered through `the_post_thumbnail()`, `wp_get_attachment_image()` or the core image block gets srcset automatically. Custom field implementations using ACF often need `wp_get_attachment_image()` rather than `wp_get_attachment_url()` to retain the responsive markup.

    For background images set in CSS, srcset does not apply. Either move the image into the HTML as an `<img>` (preferred for the LCP image especially), or use the CSS `image-set()` function with multiple density variants.

    Lazy Loading, and Why You Must Not Lazy-Load the LCP Image

    WordPress has applied `loading="lazy"` to images by default since version 5.5 (August 2020). The attribute tells the browser to defer downloading off-screen images until the visitor scrolls near them, which cuts the initial page weight on long pages by 30 to 70%.

    The critical exception: the Largest Contentful Paint image must not be lazy loaded. If your hero image, featured image, or first product image on a category page is the LCP element, lazy loading delays its discovery by 300 to 1200ms, which pushes LCP from 'good' (under 2.5 seconds) into 'needs improvement' or 'poor' territory and tanks your Core Web Vitals score.

    WordPress 5.9 and later try to detect the LCP image by skipping lazy loading on the first content image of the page. The detection is imperfect, especially on custom themes where the LCP element is a background image or a media block several elements deep. Verify with Chrome DevTools Lighthouse: run a Performance audit, find the LCP element, and confirm the `<img>` tag does NOT carry `loading="lazy"`.

    Override explicitly when you know better. In the block editor, the cover block and featured image options have a 'priority' toggle in newer versions of WordPress. For classic themes, edit the template that renders the hero and remove the lazy attribute on the hero image, or filter it out:

    add_filter('wp_get_attachment_image_attributes', function($attr, $attachment, $size) {
    if (is_front_page() && $attachment->ID === get_post_thumbnail_id()) {
    unset($attr['loading']);
    $attr['fetchpriority'] = 'high';
    }
    return $attr;
    }, 10, 3);

    This snippet removes lazy loading from the front page's featured image and marks it as high priority, which is the correct combination for an LCP hero.

    Preloading the LCP Image with fetchpriority

    Even with lazy loading off and `fetchpriority="high"` set, the browser has to discover the image before it can download it. The HTML parser finds the `<img>` tag somewhere in the body, sends the request, and the image starts downloading. On a fast connection this discovery delay is 100 to 200ms. On a 3G connection it is 800 to 1500ms.

    A preload tag in the document head removes the delay by telling the browser to start fetching the image as soon as the HTML response arrives, before the parser reaches the `<img>` tag:

    <link rel="preload" as="image"
    href="/wp-content/uploads/2026/01/hero-1200.webp"
    imagesrcset="/wp-content/uploads/2026/01/hero-600.webp 600w, /wp-content/uploads/2026/01/hero-1200.webp 1200w, /wp-content/uploads/2026/01/hero-2000.webp 2000w"
    imagesizes="(max-width: 768px) 100vw, 1200px"
    fetchpriority="high">

    The `imagesrcset` and `imagesizes` attributes (note: lowercase, not camelCase) let the browser preload the correctly sized variant for the visitor's viewport, matching what the `<img>` tag would have downloaded anyway. Without them, you risk preloading a desktop image to a mobile visitor.

    In WordPress, the cleanest way to inject this is from `functions.php`, hooked to `wp_head` at high priority:

    add_action('wp_head', function() {
    if (!is_front_page()) return;
    $id = get_post_thumbnail_id();
    if (!$id) return;
    $src = wp_get_attachment_image_url($id, 'large');
    $srcset = wp_get_attachment_image_srcset($id, 'large');
    echo '<link rel="preload" as="image" href="' . esc_url($src) . '"';
    if ($srcset) echo ' imagesrcset="' . esc_attr($srcset) . '" imagesizes="(max-width: 768px) 100vw, 1200px"';
    echo ' fetchpriority="high">';
    }, 1);

    After adding the preload, re-run a Lighthouse audit. A correctly preloaded LCP image typically cuts LCP by 400 to 1100ms on mobile and 100 to 300ms on desktop.

    Preloading interacts with caching. If your caching plugin generates static HTML, the preload tag is baked into the cached page automatically. If you use a CDN that caches HTML at the edge, verify the preload tag survives the edge transform.

    The Best WordPress Image Optimization Plugins Compared

    These are the four worth shortlisting in 2026. Everything else is either abandoned, redundant, or actively worse on file size or compatibility.

    Plugin Pricing (2026) Processing AVIF WebP Bulk Optimize Best For
    ShortPixel Free 100/mo, then 9.99 USD/10k credits API Yes Yes Yes Most sites, best AVIF support
    Imagify Free 20MB/mo, then 9.99 USD/mo unlimited API Yes Yes Yes Sites with lots of large originals
    EWWW Image Optimizer Free local, 7 USD/mo API Local or API Yes (API) Yes Yes Sites that want no API quota or fully local processing
    Smush Free, Pro 60 USD/yr API Pro only Yes Pro only Sites already in the WPMU DEV ecosystem

    ShortPixel is the default recommendation. It supports both WebP and AVIF generation, ships with an excellent CDN add-on (ShortPixel Adaptive Images), and the API quota model means you pay only for what you actually optimize. Glossy/lossy modes give you a quality slider that matches the way professionals think about JPEG quality. The bulk optimize is the fastest in the category at roughly 2 to 4 seconds per image.

    Imagify is from WP Media (same company as WP Rocket). Tight integration with WP Rocket, three quality presets (Normal, Aggressive, Ultra), and unlimited optimizations on the paid plan with no per-image credits. WebP and AVIF generation are both available. If you already pay for WP Rocket, the Infinite plan is the path of least resistance.

    EWWW Image Optimizer is the only plugin in the shortlist that can process images entirely locally without sending them to an external API, using the binaries bundled with the plugin or installed on the server. This matters for HIPAA, GDPR-strict, or air-gapped deployments where uploading to a third party is a non-starter. The API tier (which is required for AVIF and advanced WebP) is competitively priced.

    Smush is the WPMU DEV plugin. The free version is fine for basic JPEG and PNG compression and WebP conversion, but AVIF, bulk Smush beyond 50 images at a time, and the CDN require Smush Pro. Worth it only if you already have a WPMU DEV membership for other reasons.

    Never stack two image plugins. Two plugins both rewriting image URLs to point at their own optimized copies will conflict, double-process originals, and produce broken `srcset` markup. Pick one, configure it, run the bulk optimize, and uninstall any competitor.

    Image CDN Options

    An image CDN extends the optimization beyond the origin server. Instead of generating WebP and AVIF copies for every image at upload time and serving them yourself, the CDN intercepts each image request, looks at the visitor's browser and viewport, and generates and caches the right format and size on the fly.

    The three image CDNs worth shortlisting in 2026:

    BunnyCDN Optimizer is the most cost-effective. It bolts onto an existing BunnyCDN pull zone for 9.50 USD per month and adds automatic WebP and AVIF conversion, on-the-fly resizing via URL parameters, and a smart compression mode that tunes quality per image. If you already use BunnyCDN as your general purpose CDN, this is the lowest-friction option.

    Cloudflare Polish is included with Cloudflare Pro and higher plans. Polish (Lossy or Lossless) generates WebP for supporting browsers and serves the original to the rest. AVIF was added to Polish in 2024 and is now generally available on Pro plans. The advantage of Polish is zero configuration: turn it on in the dashboard and it processes every image passing through Cloudflare. The limitation: no on-the-fly resizing (that requires the separate Image Resizing product on Pro plans, with per-request pricing).

    ShortPixel Adaptive Images is the strongest pairing for sites already using the ShortPixel plugin. It rewrites every image URL to a CDN endpoint that handles format negotiation, resizing, and CDN delivery in one product. The plugin and CDN share credits, so a single subscription covers both. This is the option for owners who want one vendor to handle everything from upload compression to CDN delivery.

    For most WordPress sites in 2026, the right configuration is: an image plugin handles compression on upload and generates WebP and AVIF copies stored alongside the original; the CDN handles delivery, edge caching, and format negotiation. The plugin work is one-time at upload; the CDN work happens on every request and is what visitors actually pay for in load time.

    If images turn out to be one part of a larger speed problem (slow hosting, no caching, bloated plugins), the WordPress speed optimization service configures the full stack (hosting, caching, images, database, third-party scripts) as one engagement so the pieces work together rather than fighting each other.

    Frequently Asked Questions

    Is WebP or AVIF better for WordPress in 2026?

    AVIF when you can serve it, WebP as the fallback. AVIF files are 20 to 30% smaller than WebP at matching quality and are now supported in every major browser including Safari 16.4 and later. Generate both formats and let the browser pick via the `Accept` header. Keep the original JPEG or PNG as a final fallback for legacy crawlers and email clients.

    Does WordPress lazy load images automatically?

    Yes, since version 5.5 (August 2020). WordPress adds `loading="lazy"` to every image in post content, attachments and featured images by default. Since 5.9 it also tries to skip lazy loading on the first content image (the likely LCP element). Always verify with Lighthouse that your actual LCP image is not lazy loaded, because the auto-detection is imperfect on custom themes.

    What quality level should I compress JPEGs to?

    78 to 82 for JPEG and WebP, 55 to 60 for AVIF. Above 85 the file size jumps with no visible quality gain. Below 70 you start to see visible artifacts on photographic content. Test with a few photos at quality 78, 80 and 82; pick the lowest setting that looks indistinguishable from the original on a phone screen and a laptop screen.

    Why is my LCP still slow after enabling WebP and lazy loading?

    Most likely your LCP image is being lazy loaded by mistake, or it lacks `fetchpriority="high"`, or it is not preloaded in the document head. Run a Lighthouse audit, find the LCP element, and check the `<img>` tag's attributes. The combination of no lazy loading, `fetchpriority="high"`, and a `<link rel="preload" as="image">` in the head typically cuts LCP by 500 to 1200ms.

    Should I use an image CDN or just a plugin?

    A plugin alone is enough for small sites with a single server location and visitors in one geography. Add an image CDN once you have visitors across multiple continents, large image galleries, or measurable Time to First Byte degradation on image requests. The CDN also offloads bandwidth from the origin, which matters on shared hosting with monthly bandwidth caps.

    Can I run two image optimization plugins together?

    No. Two plugins rewriting the same image URLs will conflict, produce broken `srcset` markup, double-process originals and waste API credits. Pick one, run its bulk optimization, and uninstall any other. The same applies to image CDN conflicts: do not enable Cloudflare Polish and ShortPixel Adaptive Images at the same time on the same domain.

    Does image optimization help if my site is already cached?

    Yes. Page caching speeds up the HTML response, but the browser still has to download every image referenced in that HTML, and images are typically 60 to 80% of total page weight. Smaller, modern-format images cut bandwidth and LCP for every visitor, cached HTML or not. Image work and caching are complementary, not substitutes.

    Related Guides