How to Serve WebP Format Images in WordPress

WebP is a file format for images that provides lossless and lossy compression. If you are using WordPress, you can easily serve all images in WebP with some basic tweaks.

Most Browsers support WebP

  • According to Caniuse data, WebP is currently supported in 97% browsers include Apple Safari, Google Chrome, Opera, Mozilla Firefox, Microsoft Edge and Android browsers.
  • You can conditionally serve JPEG/PNG as a fallback for unsupported browsers.

Major Benefits of using WebP format Image

  • In comparison to the size of normal JPG or PNG image, same dimension image WebP can serve in small bytes. Hence, Images will load faster. It will be helpful especially for mobile users.
  • Serving Quality Images in few bytes, dramatically save bandwidth.
  • Keep your website updated with latest trend. Don’t loss conversation due to bull-cart slow loading issue.
  • WebP is recommended by Google Developers. Helps you in passing “serve images in next-gen format” recommendation of Google PageSpeed Insight.

This is how you can serve WebP for a WordPress site.

Serve WebP in NGINX using ShortPixel Plugin

ShortPixel plugin can help in bulk image optimization with WebP conversion and serving as per Browser support. The best part this plugin does processing on their server so it won’t slow down your site.

shortpixel webp
  • If your WordPress is hosted at Apache server user you can use .htaccess rewriting.
  • In case of NGINX you can use below rewriting rule with the help of hosting support
  • This plugin is supported with WP Rocket cache plugin as well.

First, add this block before the server directive:

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

Add this block inside the server directive:

location ~* ^(/wp-content/.+)\.(png|jpe?g)$ {
    set $base $1;
    set $webp_uri $base$webp_suffix;
    set $webp_old_uri $base.$2$webp_suffix;
    set $root "<<FULL PATH OF wp-content PARENT>>";
    root $root;
    add_header Vary Accept;
    if ( !-f $root$webp_uri ) {
        add_header X_WebP_SP_Miss $root$webp_uri;
    }
    try_files $webp_uri $webp_old_uri $uri =404;
}

Placement matters. So add it carefully.

Using WebP Express Plugin in NGINX

  • Install & Activate WebP Express, free plugin. A huge thanks to Developer.
  • Operation mode: Varied image responses.
  • Scope: Upload only.
image
  • Run Bulk Convert
image 2

For better organization of code, I would recommend place first inside /etc/nginx/ directory with name webp.conf then include in main server block.

Enter below command

cd /etc/nginx/ && nano webp.conf
  • Paste below code using right click inside nano editor in SSH Terminal.
# WebP Express rules
# --------------------
location ~* ^/?wp-content/.*\.(png|jpe?g)$ {
  add_header Vary Accept;
  expires 365d;
  if ($http_accept !~* "webp"){
    break;
  }
  try_files
    /wp-content/webp-express/webp-images/doc-root/$uri.webp
    $uri.webp
    /wp-content/plugins/webp-express/wod/webp-on-demand.php?xsource=x$request_filename&wp-content=wp-content
    ;
}

# Route requests for non-existing webps to the converter
location ~* ^/?wp-content/.*\.(png|jpe?g)\.webp$ {
    try_files
      $uri
      /wp-content/plugins/webp-express/wod/webp-realizer.php?wp-content=wp-content
      ;
}
# ------------------- (WebP Express rules ends here)
  • Press CTRL+O and Enter key to save.

Now visit main server block.

cd /etc/nginx/sites-available && ls

Edit your configuration file, and put include webp.conf; as shown below.

# General
server {
    listen         80;
    server_tokens off;
    return 301 https://$host$request_uri;
}
server {
server_tokens off;
root /var/www/html;
index index.php index.html index.htm;
server_name .gulshankumar.net;
client_max_body_size 0;

    listen [::]:443 ssl http2 ipv6only=on;
    listen 443 ssl http2;
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_certificate /etc/comodo/cert.pem;
        ssl_certificate_key /etc/comodo/private.pem;
        ssl_prefer_server_ciphers on;
        ssl_session_cache   shared:SSL:20m;
        ssl_session_timeout 20m;
        ssl_ciphers 'TLS13+AESGCM+AES128:EECDH+AES128';

error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;


# WebP Express rule goes here

include webp.conf;

# WebP Rule end

location / {
    try_files $uri $uri/ /index.php$is_args$args;
}

Reload or restart the NGINX.

service nginx reload

To quickly generate WebP files, I suggest using the WP CLI command

wp webp-express convert --allow-root

You will see output like this

Converting with the following settings:
- Lossless quality: 85 for PNG, 80 for jpeg
- Near lossless: 60 for PNG, 60 for jpeg,
- Alpha quality: 80
- Encoding: auto for PNG, auto for jpeg
Note that you can override these with --quality=<quality>, etc

uploads contains 22903 unconverted files
themes contains 2 unconverted files

Converting 22903 files in uploads
------------------------------
Converting: Lubi-Solar-Panels-Inverter-Pumps-All-Products-Price-List-500x247.bk.jpg
OK. Size: 62% of original (30 kb => 19 kb)
Converting: 32A-3-Phase-xuz-Solar-ACDB-150x150.jpg
OK. Size: 56% of original (5339 bytes => 2972 bytes)
Converting: 1MW-Solar-Power-Plant-500x281.bk.jpg
OK. Size: 86% of original (41 kb => 36 kb)
Converting: AC-SPD-320V-2-Pole-150x150.jpg
OK. Size: 55% of original (3149 bytes => 1734 bytes)
Converting: Bhanwar-Portfolio-150x150.jpg
OK. Size: 71% of original (6513 bytes => 4638 bytes)
Converting: Solar-power-768x614.jpeg
OK. Size: 73% of original (87 kb => 64 kb)
Converting: 1kW-Luminous-Solar-Panel-Off-Grid-Complete-System-1500VA-300x225.jpg
OK. Size: 56% of original (14 kb => 7744 bytes)
Converting: xuz-Solar-2-in-1-T2-MC4-Y-Branch-Connector-min-1170x350.bk.jpg
OK. Size: 35% of original (16 kb => 5714 bytes)

Things to note

  • If you use BunnyCDN, must enable Vary Cache.
bunnycdn vary cache
  • Cloudflare doesn’t support Vary Cache. Try below alternative approach.

Use WebP using Cloudflare CDN (Without Plugin)

If you’re a Cloudflare Pro user you can simply enable WebP in one-click from Speed Tab.

cloudflare webp

Serve WebP using BunnyCDN Optimizer (Without Plugin)

BunnyCDN offers Optimizer services which comes with On-the-fly WebP serving solution. It’s one-click solution for $9.5/mo additional cost.

bunnycdn webp

Serve WebP using JetPack Plugin

  • Simply install and activate JetPack plugin
  • Enable the Site Accelerator.
jetpack webp

You may notice downgrade in image quality that can be fixed using below filter.

Serve WebP using Imagify

Imagify is an Image Optimization plugin offered by WP Media, the folks behind WP Rocket.

  • Install and activate Imagify plugin
  • Enter the API Key
  • In settings, choose Picture tags mode for quick setup.
  • Alternatively, you can use rewrite rule with some server configuration as described here. With Apache, the .htaccess code addition process will be automatic but with NGINX you need to do manually.
imagify plugin webp settings

WebP to JPG

WebP may degrade image quality a bit in some cases. If you want to revert back from WebP to JPG, simply follow these steps.

  • Deactivate & Delete WebP related plugin.
  • Remove its related setup from configuration file (.htaccess)
  • Bulk delete .webp files and save disk space.
find . -type f -name "*.webp*" -delete

If you want to convert WebP file to JPG, you can use tool available at CloudConvert.


Manual method without Plugin

This section is for information purpose only.

Step 1 : Adding WebP format in HTML Document

First, you need to convert your all images in WebP and along with your previous image format as the fall-back. There is  some plugin like Optimus which can do this job automatically. But, I will show an another easy to do this manually.

  1. Go to this website image.online-convert.com/convert-to-webp
  2. Paste your Image Link and click on convert. Your WebP format images will be downloaded
  3. Now edit the raw HTML code where your normal Image is appearing.

Let say, in beginning your Image HTML code was like this

<img src="https://www.gulshankumar.net/wp-content/uploads/2016/09/webplogo.png" alt="gulshan kumar" width="186" height="66" />

You need to wrap above code with little more HTML markup.

<picture>
	<source srcset="https://www.gulshankumar.net/wp-content/uploads/2016/09/webplogo.webp" type="image/webp" />
	<img src="https://www.gulshankumar.net/wp-content/uploads/2016/09/webplogo.png" alt="gulshan kumar" width="186" height="66" />
</picture>

Now, Your HTML document is ready to serve images in WebP format.
Step 2 : Configure server settings
Just one more step, you need to configure some Apache Webserver settings via .htacccess so browser and web server can treat it properly like all other images.

Your Web Hosting server may don’t know from which mime type this kind of format images they need to serve. So must add proper mime type. Also, it would be worth to setup expiry header for caching.

# Serve Images with correct Mime Type
AddType image/webp .webp

# Setup Cache
ExpiresActive On
ExpiresByType image/webp A2592000

Kindly note: Make sure you’re using WordPress 5.8 or later.

If you’re using WordPress older than version 5.8 it doesn’t support uploading of WebP format image. You may get error “This file type is unfortunately not allowed for security reasons” while uploading .webp images.

So, must fix this issue by adding this code in your theme functions.php It would be helpful in case if you will upload your images directly from WordPress Dashboard > Media option.

function webp_upload_mimes( $existing_mimes ) {
	// add webp to the list of mime types
	$existing_mimes['webp'] = 'image/webp';

	// return the array back to the function with our added mime type
	return $existing_mimes;
}
add_filter( 'mime_types', 'webp_upload_mimes' );

Done.

If you need any help, please look at comment section. It would be my pleasure to help you.

Additional notes

  • If you’re a Cloudways user, you cannot deliver WebP with .htaccess rewrite because they use NGINX specifically for static files. In this case you have two choices. Ask hosting team to edit configuration file for you or use JavaScript or 3rd-party CDN based solution such as Bunny or CF.

Further readings
If you are curious to learn more about WebP, please refer these links.

Thanks.

Leave a Comment

51 thoughts on “How to Serve WebP Format Images in WordPress”

  1. i’m custom manual edit <img src="i0 .wp .com/ all in theme.

    it free and resize on-the-fly and webp served and save datatransfer hosting, good without plugin. XD

    can u write regex/replace to function.php? thx.

    Reply
  2. First, thanks for the thorough article. I have a WP site (Elementor/RevSlider) and WP-Rocket has already improved it a lot, but the “next gen images” is a pending matter. Usually with the fab WebP Express everything is solved but this is hosted on Kinsta, which is nginx. I need to work that out, your article may help. Kinsta also has a (Cloudflare?) CDN so I’m trying to figure out how it all goes together, as the CDN produces webp images itself.. but won’t offer the fallback jpg/png as far as I know. How should I go about this in the most simple way if you have any tip? Thanks again!

    Reply
    • Hi charlyarg,

      Thank you for writing comment at my WebP article.

      Kinsta provides an Automatic Image Optimization feature with WebP delivery, which can be utilized if you have Kinsta CDN enabled. The Kinsta CDN operates using Cloudflare Enterprise, which serves WebP images and reverts to traditional versions for browsers that do not support it.

      Summary: You do not need to use any plugin for WebP. Just turn on Kinsta CDN.

      Best regards,
      Gulshan

      Reply
      • That would be awesome Gulshan! Were you able to test it somehow? The docs about it in Kinsta are not clear about the fallback image. In any case I’m asking the Kinsta support for a confirmation (taking a while :D). It would be a great an simple solution!

        Reply
        • I confirmly know that Kinsta CDN (Actually, Cloudflare Enterprise) does support WebP with fallback. I do not have Kinsta account right now to perform this test but I do have personal experience with Cloudflare Free, Pro, Business and Enterprise plan features.

          Reply
  3. WebP has such a nuance – not all browsers support it.
    For example, some versions iOS Safari, regular Safari, IE – do not support WebP.
    https://caniuse.com/#feat=webp
    Therefore, you must always store at least two versions of each image. Webp (for WebP-enabled browsers) and original image.
    And give the right version depending on the browser.
    And the original image must also be optimized/compressed – so that even for browsers without WebP support, images will be optimized (lighter in weight) – this is the third! version of the file..
    At the optipic service, I recently noticed a new plugin in which all of this is already in the box.
    https://optipic.io/en/webp/wordpress/
    You can even connect everything so that the urls of the images do not change (they remain exactly the same and look like internal urls on my site). But in fact, they are loaded through their system with automatic compression, conversion to webp and recognition of webp support.
    It turns out that everything is simple and beautiful, and inexpensive))

    Reply
  4. I didn’t try the webp format as of now in WordPress. But now after reading this post I will try to implement it. I will compare the image quality from other formats as well. Thank you for sharing this article.

    Reply
  5. I have a question about ShortPixel method.

    I use Plesk panel with NGINX
    There is a section called Additional nginx directives
    Here you can specify the settings for the nginx reverse proxy server that runs in front of Apache. Your directives will override the server-wide nginx configuration. For example, you may want to change the connection timeout or to pack requests with gzip. Use the same syntax as you use for nginx.conf. For example, if you want to pack all the proxied requests with gzip, add the line: ‘gzip_proxied any;’.

    https://i.imgur.com/OLWu9bJ.png

    can i add codes there i dont know?

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

    location ~* ^(/wp-content/.+).(png|jpe?g)$ {
    set $base $1;
    set $webp_uri $base$webp_suffix;
    set $webp_old_uri $base.$2$webp_suffix;
    set $root "<>";
    root $root;
    add_header Vary Accept;
    if ( !-f $root$webp_uri ) {
    add_header X_WebP_SP_Miss $root$webp_uri;
    }
    try_files $webp_uri $webp_old_uri $uri =404;

    You used these sentences!
    before the server directive and inside directive.
    I read your Installing WordPress at NGINX topic so
    If i try to add these from codes is this right?

    map $http_accept $webp_suffix {
    default "";
    "~*webp" ".webp";
    }
    server {
    listen 80;
    return 301 https://$host$request_uri;
    }
    server {

    location ~* ^(/wp-content/.+).(png|jpe?g)$ {
    set $base $1;
    set $webp_uri $base$webp_suffix;
    set $webp_old_uri $base.$2$webp_suffix;
    set $root "<>";
    root $root;
    add_header Vary Accept;
    if ( !-f $root$webp_uri ) {
    add_header X_WebP_SP_Miss $root$webp_uri;
    }
    try_files $webp_uri $webp_old_uri $uri =404;
    }
    # Document Root
    root /var/www/html;
    index index.php index.html index.htm;
    server_name .example.com;
    client_max_body_size 0;

    listen [::]:443 ssl http2 ipv6only=on;
    listen 443 ssl http2;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:20m;
    ssl_session_timeout 20m;
    ssl_ciphers 'TLS13+AESGCM+AES128:EECDH+AES128';

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location / {
    try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~* .php$ {
    if ($uri !~ "^/uploads/") {
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    }
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    }
    location = /favicon.ico {
    log_not_found off;
    access_log off;
    }

    location = /robots.txt {
    log_not_found off;
    access_log off;
    allow all;
    }

    location ~* .(css|gif|svg|ico|jpeg|jpg|js|png)$ {
    expires 1y;
    log_not_found off;
    }

    # Enable Gzip compression.
    gzip on;

    # Disable Gzip on IE6.
    gzip_disable "msie6";

    # Allow proxies to cache both compressed and regular version of file.
    # Avoids clients that don't support Gzip outputting gibberish.
    gzip_vary on;

    # Compress data, even when the client connects through a proxy.
    gzip_proxied any;

    # The level of compression to apply to files. A higher compression level increases
    # CPU usage. Level 5 is a happy medium resulting in roughly 75% compression.
    gzip_comp_level 5;

    # Compress the following MIME types.
    gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;
    }

    Is this right?
    And what do you think about plesk how i use webp at plesk?
    Thanks

    Reply
  6. Hi, this is a good article, but
    It is better to install the plugin or put the code directly for webp
    This way, each image does not create two urls. Does it cause a problem in the SEO site?

    Reply
  7. Hey Gulshan Kumar ,

    Awesome post with good information. It is my first time commenting on your blog post and am glad to say that you have done a fabulous work and provided helpful & easy tips to serve webp format images in WordPress. I really like and appreciate the way you have explained the things in such a step-by-step process making the concept very clear and easy to understand. while scrolling through your blog post i have noticed that you have also discussed about the major benefits of using webp format image that are also providing good understanding. You have explained all the vital things in an easy language that are true enough to understand and educate the readers.

    After going through this complete guide i really gain ideas and am sure that this post is definitely going to help lots of people & especially WordPress-users to sort out their query. Good work and keep sharing more similar post.

    Eventually thanks for sharing your knowledge, ideas and such an informative post.

    Regards
    -Aadarsh

    Reply
  8. I have tried this method to enable WebP format images on my site, but I am encountering some unknown error. My site showing a low score on google page speed insight.

    Reply
    • May I know please which specific method you have tried? Also, please share the screenshot of error. I will try my best to help you.

      Reply
  9. It works great in Chrome and Firefox on the PC/Laptop. BUT, the webp images are not displayed on iPhone (Chrome and Safari)

    Reply
    • Safari is not supporting webP. Chrome on iOS is based on Safari, too. So webP won‘t work on iOS at all and you have to serve a fallback image.

      Reply
  10. Hi,

    I am not quite clear on where this needs to be inserted. I am looking to Optimise my header image to Webp. Is there a video or screenshot based write up on how I can include this?

    Would really appreciate the help

    Regards
    Shwetha

    Reply
  11. Hello Gulshan,

    Thanks for sharing this article.

    I did follow the steps mentioned in here in this format.

    But the image is not appearing on Firfox, and IE. Did I miss any thing in here.

    Please suggest.

    Reply
  12. Hi..Just wondering if i need to edit each image tag or is there somewhere in my theme templates this could be done.
    Any guidence would be great.
    Thanks
    Mark

    Reply
  13. Hi Gulshan,

    Even after putting the code snippet in the function.php file.

    I still have the same error message when I try to upload webp format. The message is “sorry this file type is not permitted for security reasons”.

    Can you help fix this?

    Thanks.

    Martin

    Reply
    • Hello Martin,

      At my end it’s working fine. For a demo, I have sent a quick video on your email. Please check and revert back if I can help with any thing else.

      Thanks

      Reply
  14. I haven’t added anything except the last code from your post in function.php to support Webp format on all of future media uploads. Do I need to add any thing else ? or will it create any kind of issue for users whose browsers are yet unsupported to this format?
    anyway keep up the good work 😉

    Reply
    • That’s all. Now you can easily upload webp directly in your WordPress Dashboard. No extra things to do. Just feel free to use it with picture HTML tag. So, it will support for all browsers, without any issues. Thanks

      Reply
  15. The problem with the suggested HTML implementation is that Chrome will make two requests, one for WEBP and another one for JPEG resulting in double requests and increasing the page load time.

    Reply
    • Hey dear,

      It doesn’t create two requests(as you are saying) instead it automatically serve only one type image format either WebP or JPEG according to HTTP accept type.

      I’d suggest please try one more time and look carefully at Network Timeline in the browser console. If you see there are double requests, please email me your HTML code and timeline screenshot also. I’d love to review it. I believe it should work fine for you too.

      Thanks & Regards,
      Gulshan

      Reply
      • I installed the code into the functions.php. And as you said it did allow me to upload in my WP theme. The problem is that the image doesn’t allow cropping so it won’t allow me to use it on the site.

        Reply