EWWW IO and WebP Images

Unlike the other conversion options, WebP conversion is possible for every PNG, JPG, and GIF image on your entire WordPress site. It is not limited to the Media Library. So theoretically, you could put the root path to your WordPress site in folders to optimize, run a Bulk Optimize, and EWWW IO would create WebP copies of all images where WebP is the smaller of the two formats.

Easy IO Sites

When the Easy IO CDN is enabled on your site, no further configuration is necessary. You do not need any other WebP options, and you do not need to run a Bulk Optimize. All WebP images will be stored on our CDN servers, which saves you space, and a lot of time. You can stop reading now, and go do something fun!

Conversion vs. Delivery

There are two things we need to do to get WebP images to your visitors:

  1. WebP Conversion - this will make copies of your images in the WebP format, and happens automatically for new images, while existing images can be converted with the Bulk Optimizer.
  2. WebP Delivery - any delivery method should make sure supported browsers get a WebP image, and older browsers still get an image that they can display (JPG, PNG or GIF).

WebP Conversion

Converting JPGs to WebP involves a slight quality loss, but that isn't usually noticeable. On the other hand, converting a PNG to WebP is completely lossless by default, but if you want more compression, you can use the EWWW_IMAGE_OPTIMIZER_LOSSY_PNG2WEBP override (define it as true in your wp-config.php).

WebP conversion does NOT replace your images, it only makes a copy of the original with the exact same name, but in the WebP format and with a .webp extension added onto the end. Why?

First, while all modern browsers currently support WebP, there will likely be folks visiting your pages with older versions of those browsers, and we're not a huge fan of broken images, even if folks ARE on an older browser. Second, the plugin will only create the WebP images if they are smaller than the original format (JPG or PNG), and while the WebP format works well for most images, it does not work for ALL images.

WebP Delivery

While conversion is relatively straight-forward, WebP delivery can get more complex. The rest of this article will deal primarily with the various delivery solutions.

There are several delivery/rewriting options available directly in the plugin, Apache/Litespeed rewrite rules (.htaccess), JS WebP Rewriting, and <picture> WebP Rewriting.

SiteGround Hosting

If you use SiteGround (and their new Site Tools console), you can enable built-in server-based WebP delivery, with no further action required (beyond converting your images to the WebP format).

Cloudways Hosting

2021/08/06 - Do not use .htaccess rules on Cloudways servers, as their caching system cannot "vary" the content between webp & jpeg/png to support older browsers. This also has the potential to impact third-party systems that attempt to embed your images like Slack, Facebook, Twitter, etc.

Rewriting with Apache & Litespeed

Most web servers run Apache (or Litespeed), and for those sites, the EWWW IO plugin can attempt to modify the rewrite rules in your .htaccess file to send WebP images to supported browsers (if such a file exists). When you enable WebP conversion, the rewrite rules will be displayed, but only if your site does not use Cloudflare. The plugin will also display a test image by the WebP settings: a red PNG image indicates the server is not sending WebP images, or your browser does not support them.

When you insert the rules, you will get a success message if it worked, and it will attempt to reload the test image. It may sometimes be necessary to reload the page to get the right test image to load. When you're using a native Apache or Nginx rewrite solution like this, the image URLs in your page will not change. The rewriting happens (in place) when the visitor's browser actually requests the image.

*EWWW IO will also attempt to automatically verify whether your server is delivering WebP images properly (helpful if your browser is being stubborn and not letting you see the green WebP image).

This video demonstrates two of the WebP delivery methods, and how to verify that they are working (<picture> WebP can be verified much like JS WebP, by looking at the actual filenames):

If you're running a multisite WordPress install, you may have to put the rewrite rules above your Wordpress rules for them to take effect. And if the rewrite rules aren't working, you can try the JS WebP Rewriting instead. 

Rewriting (via map) with Nginx

EWWW IO can't directly modify your Nginx configuration, so the solution is a bit different for Nginx. You need to potentially modify three different files here:

First, we need to add a map directive to your http config, usually /etc/nginx/nginx.conf (make sure you put it inside of the http{} section/block):

map $http_accept $webp_suffix {
  default "";
  "~*webp" ".webp";

That tells Nginx to set $webp_suffix to ".webp" if the browser's Accept header contains "webp". The second change is to be sure that Nginx knows what a .webp file is. While newer versions of Nginx should already recognize the WebP format, we need to modify the mime.types file (also in /etc/nginx/) to tell Nginx about this new file type. Look for this line, and add it if you can't find it:

image/webp	webp;

The last change is to setup a location block within your server block to handle PNG and JPG images that might have WebP versions. If you only have one server block, it is usually located in /etc/nginx/sites-enabled/default. Add this within the server {} section:

location ~* ^.+\.(png|jpe?g)$ {
  add_header Vary Accept;
  try_files $uri$webp_suffix $uri =404;

This tells Nginx to apply the enclosed rules to any files that end with png, jpg, or jpeg. If you have .jpe files, add a second question mark after the g, so it looks like "jpe?g?". The first rule adds the "Vary Accept" header to the return response, which is what allows supported CDNs to cache different files for the same URL. The second rule tells Nginx to look for a file that matches the original URL/URI with our $webp_suffix appended (.webp), and if that fails, to just deliver the original URI or fallback to a 404 if the file doesn't exist at all.

Just like any server-based delivery method, your image URLs do not change, but the content (and corresponding content-type) will show as WebP:

JS WebP Rewriting

If your web host features any sort of server-level caching solution, you deliver your images through a CDN (content distribution network), or you use a cloud security service like Cloudflare or Sucuri, you may not be able to use the (above) rewrite rules. Instructions for known-working CDNs can be found below.

For such cases, JS WebP can be used to dynamically change the image URLs based on whether the visitor's browser supports the WebP format. This method may not work with some themes/plugins, so let us know if you find any conflicts!

Unlike server-based delivery, JS WebP and <picture> WebP do change your URLs. But your server may not know what a WebP image is, resulting in this bit of odd behavior:

In this case, the file extension is your confirmation that things are working correctly, and you can ignore the Content Type displayed by your browser.

Lazy Loading

When JS WebP is used with our built-in lazy loader, you get smaller images plus less page weight. JS WebP is also compatible with these lazy load plugins.

Server-level Caching

WP Engine uses server-level caching on all accounts by default. You can ask them to setup WebP rewriting rules for you, or just use JS WebP Rewriting.

Known working CDNs

The Cloudfront CDN from Amazon (not to be confused with Cloudflare) can support WebP images without the JS WebP (unless it is used with S3, see next paragraph for that scenario). To enable Cloudfront to operate with any of the rewriting rules above, you need to make one small change in your Distribution settings. Under the Behavior tab, select the Behavior and click the Edit button. Choose Whitelist from Forward Headers, and then add the "Accept" header to the whitelist.

If you use Cloudfront with Amazon S3, it can get a bit more complicated, unless you use WP Offload Media. If you are using WP Offload Media, and have local copies of your images, you can just enable JS WebP Rewriting and EWWW IO will auto-configure itself to work with your S3/Cloudfront URLs. If you use WP Offload Media, and do NOT have local copies of images on your web server, you need to enable Force WebP, run a bulk optimize, and then enable JS WebP Rewriting.

If you use a different Cloudfront/S3 plugin or setup, you will need to use the WebP URLs setting detailed below. If you do not keep local copies of your images on your web server, you will also need the Force WebP option. Additionally, if you use Force WebP mode, you must run a bulk optimize to make sure every single image has a .webp copy, because the JS WebP Rewriting will blindly rewrite every Cloudfront image url to point at the .webp version (for supported browsers only though). Once you know that all your images have .webp copies, you can then enable JS WebP Rewriting and configure WebP URLs as described below. 

In any case, the easiest method with Amazon S3 is to use Easy IO in front of your S3 bucket instead of Cloudfront, with no extra configuration.

StackPath & MaxCDN have an option within the zone/site settings to support WebP images as well. They don't create any .webp images, so you'll need to generate those on the origin/local server using the bulk optimizer, and then implement the .htaccess rules for Apache, or the above rules for Nginx.

BunnyCDN has an option within the Pull Zone Cache to Vary Cache based upon Browser WebP Support which allows you to use server-side rewrite rules in Apache/Litespeed & Nginx.

KeyCDN has a Cache Key WebP setting that works with the .htaccess rules for Apache, or the above rules for Nginx.

Cloudflare requires the JS (or <picture>) WebP Rewriting function or you can use their Polish feature, which is available on their paid plans.

The Cloudways CDN cannot currently deliver WebP images without one of the methods in the next paragraph.

If your CDN does not honor the Accept header, you should use the JS WebP Rewriting option. The same applies if you have any sort of proxy/caching server that is in front of your actual web server. This is a JavaScript solution that will parse your page looking for images that have WebP copies. There is also a WebP option in our SWIS Performance plugin that works nicely with page caching and proxy servers, but it still requires local copies of the images. Which leads us to the other two options...

WebP URLs & Force WebP

So, what are these other two options for? Let's address WebP URLs first, and then come back around to Force WebP, which is our last resort. Note that these options are only available in Ludicrous Mode, though they will be auto-configured if you use WP Offload Media.

The WebP URLs setting is needed by JS WebP & <picture> WebP Rewriting if your image URLs (addresses) are rewritten to point at your CDN before WebP rewriting happens. The WebP parser needs to reverse engineer your URLs back to file-system paths, so that it can check if a .webp image exists. For example, it would try to convert https://example.com/wp-content/uploads/2024/10/image.jpg to something like /var/www/wp-content/uploads/2024/10/image.jpg so that it can check to see if /var/www/wp-content/uploads/2024/10/image.jpg.webp exists. It does so by replacing your normal site URL (https://example.com) with the location of your website on your server (/var/www/ in the example). BUT, if your images are on a CDN like cdn.example.com, then the plugin needs to know that it should look for cdn.example.com instead of just example.com.

*Note that WebP URLs will not be visible unless you've selected JS WebP or <picture> WebP.

So, let's say your CDN domain is cdn.example.com, then you would simply enter https://cdn.example.com/ in the WebP URLs setting.

However, if you use a different folder on your CDN than you do on your server, then you need to include the folder too. If your CDN image URLs look like https://cdn.example.com/files/2024/10/image.jpg compared to https://example.com/wp-content/uploads/2024/10/image.jpg, then you want to add https://cdn.example.com/files/ in the WebP URLs.

What was that about Force WebP?

As mentioned, none of this will work if you do not have local copies of your images. To get around that requirement, you first need to use the Force WebP option to make EWWW IO create WebP versions of every image on your site.

Then, choose whether you are going to use JS WebP or <picture> WebP. After that, you need to add your CDN URL in the WebP URLs box. Do not add your CDN URL to the WebP URLs until after you have used the bulk optimizer to create copies of all your images in the WebP format, or you'll have broken images on your site.

Once you've done that, enable JS WebP (or <picture> WebP), so that the plugin will rewrite any images that match the URL patterns you’ve listed. Both options will provide a fall-back for older browsers, so you can go do cartwheels (or whatever you enjoy)!

AMP (Accelerated Mobile Pages)

AMP has this fabulous 'fallback' attribute that allows you to wrap one image element inside another. Then if the first image cannot be displayed, the second one loads instead. The AMP Project Docs even show an  example of this, but it doesn't really work properly. The problem is that unsupported browsers will still load the webp image, and only then, after you've wasted precious mobile data, does it load the original (fallback) image.

Fortunately, any server-based WebP delivery method will still work with AMP, and that's the cleanest option anyway. If the Apache/Nginx rules are a non-starter, for example, if you're using Cloudflare, there are a couple different options. You can use our Easy IO CDN for automatic WebP conversion & delivery, or you can also use Cloudflare's Polish feature (available on Pro plans).

Advanced Tweaks

Sharp YUV

There are some cases where the compression from WebP doesn't fare so well, notably sharp edges from text and graphic overlays, and areas of very bright colors. Fortunately, there is a solution that generally works quite well for these cases, which is to enable the Sharp YUV encoding option. In EWWW IO this can be done with the EIO_WEBP_SHARP_YUV constant. Define it to true in your wp-config.php like so:

define( 'EIO_WEBP_SHARP_YUV', true );

External CSS images

There may be other uses for this, but if you have image URLs in external CSS files and can't use server-based rewriting (like Apache .htaccess rewrites or Nginx server rules), you might be a bit stumped. In order to help third-party developers, when you use JS WebP Rewriting, we add a "webp-supported" class to the body tag. This lets you target .webp version of background images based on the webp-supported class, and use non-webp images otherwise.