Converting WordPress Uploads to WebP

There are plenty of options when it comes to optimizing your images. With Kinsta, a single click from their built in CDN and all images will be served out using the most optimization version. Jetpack plugin has a similar feature called Site Accelerator which utilizes WordPress.com’s CDN. What if you want options to do this yourself? I previously wrote about a way to convert images over the command line using ImageOptim’s API. Today let’s look at a different approach by doing an in-place image replacement using the WebP format.

WebP is a very efficient image format which many optimization services use.

Many optimization services will convert images to WebP format. This results in a similar image with very little noticeable loss in quality. Open up your command line and give it try. If your computer doesn’t recognize the cwebp command then refer to https://developers.google.com/speed/webp/download for installing it.

cd ~/Photos/
ls *.jpg       # pick any JPG you see in the list
cwebp -q 80 image_name.jpg -o image_name.webp

Bulk conversion with a bash script

The following is an example of running a bulk conversion over SSH on a WordPress site hosted with Kinsta. The script works by finding all images over 1MB in the uploads and in-place converting them to webp. The file extension remain the same as to preserve compatibility with existing URL references.

The same process should work for any web host with SSH access however some of the paths will need adapted for your use case. Start by accessing your site with SSH, and then create ~/private/bulk-convert-to-webp.sh with the following code. Then chmod +x ~/private/bulk-convert-to-webp.sh to grant execute permissions and ~/private/bulk-convert-to-webp.sh to run. 

#!/bin/bash

if ! which cwebp &> /dev/null
then
    cd ~/private
    if [ -f "libwebp-1.4.0-linux-x86-64/bin/cwebp" ]
    then
        cwebp() {
          ~/private/libwebp-1.4.0-linux-x86-64/bin/cwebp "$@"
        }
    fi
    if ! cwebp --version &> /dev/null
    then
       wget --quiet https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.4.0-linux-x86-64.tar.gz
       tar -xvzf libwebp-1.4.0-linux-x86-64.tar.gz
       cwebp() {
          ~/private/libwebp-1.4.0-linux-x86-64/bin/cwebp "$@"
       }
   fi
fi

cd ~/public

before_size="$( du -sh wp-content/uploads/| awk '{print $1}' )"
echo "Current uploads size: $before_size"
files=$(find wp-content/uploads/ -type f -size +1M \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \))
count=$(echo "$files" | wc -l)

if [[ $files == "" ]]; then
   echo "No images found."
   return
fi
echo "Total number of photos over 1MB: $count"

echo "$files" | while IFS= read -r file; do
    format=$( identify -format "%m" "$file" )
    if [ "$format" == "WEBP" ]; then
        continue;
    fi
    before_size=$( du -sh --apparent-size "$file" | awk '{print $1}' )
    ~/private/libwebp-1.4.0-linux-x86-64/bin/cwebp -q 80 "$file" -o "$file.temp.webp" > /dev/null 2>&1
    # Check if the conversion succeeded and the temporary file is non-zero in size
    if [ -s "$file.temp.webp" ]; then
        # Move the temp file to the original file, overwriting it
        mv "$file.temp.webp" "$file"
    else
        # If conversion failed, remove the empty temp file
        rm -f "$file.temp.webp"
        echo "Conversion failed for $file"
        continue
    fi
    after_size=$( du -sh --apparent-size "$file" | awk '{print $1}' )
    echo "Converting from $format to WEBP ($before_size -> $after_size): $file"
done

after_size="$( du -sh wp-content/uploads/ | awk '{print $1}' )"
echo "Uploads reduced from $before_size to $after_size through bulk WEBP conversion"

Here is a sample response when I ran on a rather large customer website which had already been optimized with other image optimization plugins.

Current uploads size: 165G
Total number of photos over 1MB: 65305
...
Converting from JPEG to WEBP (1.6M -> 211K): wp-content/uploads/2015/11/05.jpg
Converting from JPEG to WEBP (1.4M -> 134K): wp-content/uploads/2015/11061.jpg
Converting from JPEG to WEBP (2.1M -> 316K): wp-content/uploads/2015/06/17.jpg
Converting from JPEG to WEBP (1.1M -> 145K): wp-content/uploads/2015/06/15.jpg
Converting from JPEG to WEBP (2.2M -> 344K): wp-content/uploads/2015/06/17.jpg
Uploads reduced from 165G to 144G through bulk WEBP conversion