How To Convert WordPress Images to WebP Locally

These are steps to convert your JPEG, JPG, and PNG images to WebP format. Locally, means that you will be converting them to WebP on your own local computer, and then uploading the new files up to your server.

Why do it locally?

Compressing your images to WebP locally allows you to use the compression method option (-m 6). According to Google, setting the compression method to 6 will be slower while making the conversion, but it can result in a smaller WebP file size, and a higher compression quality. This is what you want on your site for the most optimized images.

Understand The Task

This does nothing for future uploads, and will not convert any images that you upload later. This task is only a one-time conversion for existing images.

Prerequisites

  • Most of these steps are done on the command line. You’ll need a Unix-based shell.

  • You need to have installed cwebp which is the WebP encoder tool developed by Google.

  • These steps are written for a site that has all uploads in one folder without a sub-directory. In other words, the Media Settings in WP admin has a setting to “Organize my uploads into month- and year-based folders.” That setting must be unchecked for these steps to work as is.

    Note: Of course, if you do have that setting enabled, then you can go through the commands on this page and modify them to make them recursive to work month- and year-based folders, but you’ll then have to do the same for the 2 plugins which are used below (in step 1 and step 10).

  • Since we’re doing the conversion locally, you need to have a local copy of your WordPress wp-content folder on your computer. You may have a local development version of your entire site, which is fine, but we’ll just be working on the wp-content/uploads folder.
  • You agree that I assume no liability over your images or your site.

The Steps Begin Here

  1. You need a list of all image files that need to be converted to WebP. This means all the images that WordPress knows of, and that exist in the Media Library. That is, all attachments, featured images, images inserted into post content, and all extra sizes including thumbnails and any custom sizes. But you only want to list images of type JPEG, JPG, or PNG. You do not want to list any existing WebP images, nor GIF, nor other formats.

    To get this list, use this plugin. This is a quick one-time-use plugin which you can delete right after. Just follow those 5 steps at that link.

  2. Copy the files to be manipulated to another directory which we’ll name uploads_copy. We’re not going to copy all of the uploads. We’re only going to copy the ones that are listed in the list from the previous step.

    IMPORTANT: First update your local uploads folder to match the server (sync remote to local).

    Then, on the command line:

    Change to your local wp-content directory.

    command line

    cd path/to/wp-content

    Make a new folder to hold the images to be converted.

    command line

    mkdir uploads_copy

     
    Copy the images from your uploads folder into the new uploads_copy folder.

    Mandatory edit to this next command: you must change /path/to/wp_images.txt to the correct path to wp_images.txt on your own computer. wp_images.txt is the file you downloaded in step 1.

    command line

    for file in $(</path/to/wp_images.txt); do cp "uploads/$file" uploads_copy; done
  3. Optional. Note the number of files to be manipulated. This is just so you can compare the number of files later.

    Count total number of files:

    command line

    ls uploads_copy | wc -l

    … or by file extension:

    command line

    find -type f -path '*uploads_copy/*' | sed -e 's/.*\.//' | sort | uniq -c
  4. Convert all images in uploads_copy to WebP with 100% quality and a compression method value of 6. You can change the quality from 100 to whatever you want, and you can omit the compression method option (-m 6) if you’re not comfortable with it.

    Note that this is the big step. It will take a long time depending on how many images you have. You should probably go have a meal while this command is running.

    `for file in uploads_copy/*; do cwebp -m 6 -q 100 -lossless -exact "$file" -o "${file%.*}.webp"; done`
  5. Check if any images did not get converted. If all images were converted successfully, this next command should return nothing:

    for f in uploads_copy/*; do [[ $f == *.webp ]] && continue; [ ! -f "${f%.*}.webp" ] && echo "Did not convert ${f##*/}"; done

    If any WebP image was not created, you can convert one image manually like this:

    cwebp -m 6 -q 100 -lossless -exact image_name.jpg -o image_name.webp

    …but change image_name.jpg to the name of the original image, and change image_name.webp to the name of the original image but instead with the webp extension.

  6. Optional. Confirm that the total number of files doubled. You should compare these numbers to the ones you got in step 3.

    Count total files:

    ls uploads_copy | wc -l

    … or count by file extension:

    find -type f -path '*uploads_copy/*' | sed -e 's/.*\.//' | sort | uniq -c
  7. Check that the new WebP files are actually smaller than the original. If not, compress the original again to a quality of 85%, then check their sizes again. Then, delete the original JPEG/JPG/PNG images.

    To complete step 7, go through this list:

    • Step 7a.

      Change to the uploads_copy directory:

      cd uploads_copy
    • Step 7b.

      For each set of images (a set means an old image and its new WebP), delete the larger of the two.

      for j in $(for i in $(find . -exec bash -c 'basename "$0" ".${0##*.}"' {} \; | sort | uniq --repeated); do find . -name "$i*" -printf '%s %p\n' | sort -nr | head -1 | cut -d ' ' -f 2-; done); do rm "$j"; done
    • Step 7c.

      Optional. Confirm that the total number of files is back down to original number from step 3.

      Count total files:

      ls | wc -l

      … or count by file extension:

      find -type f | sed -e 's/.*\.//' | sort | uniq -c
    • Step 7d.

      If any remaining file is not WebP, it means that the new WebP actually came out larger than the original image. So we compress the original file again, but this time to a quality of 85%.

      for f in *; do [[ $f == *.webp ]] && continue; cwebp -m 6 -q 85 -lossless -exact "$f" -o "${f%.*}.webp"; done
    • Step 7e.

      Repeat steps 7b and 7c.

    • Step 7f.

      Here, we decide to keep whatever JPEG/JPG/PNG original files are smaller than the new WebP because in the end its about filesize, not which extension to use, Google Pagespeed Insights be damned. So, delete all remaining non-WebP files in here since you don’t need these because you have the originals in your real uploads folder.

      for f in *; do [[ $f == *.webp ]] && continue; rm "$f"; done
    • Step 7g.

      Confirm that only WebP files remain:

      find -type f | sed -e 's/.*\.//' | sort | uniq -c

      …and no directories:

      find . -maxdepth 1 -type d -print

      …and nothing hidden:

      ls -d .*
    • Step 7h.

      To complete step 7, change back to the directory one level up.

      cd ../
  8. Move the new WebP files from the uploads_copy directory back to the uploads directory.

    First check that no same WebP image file already exists in the uploads directory:

    dup=0; for filename in uploads_copy/*; do fn=$(basename "$filename"); if [ -f "uploads/$fn" ]; then echo "$fn already exists in uploads"; dup=$((dup + 1)); fi; done; if [ "$dup" -eq "0" ]; then echo "No duplicates exist."; fi

    Move the images:

    mv -v uploads_copy/* uploads/
  9. Upload the new WebP files to the server, but don’t delete original JPEG/JPG/PNG ones yet from your server. For example, you can upload the new WebP files via FTP.

    (If you plan to do this by syncing your uploads directory from local to remote, you must first be sure that you did the important first sync in Step 2. If you forgot to do it before, do not do it now because then you would delete all the new WebP files and have to start over from Step 2.)

  10. Now that you’re done converting the actual image files and uploading them to your uploads directory, you need to let WordPress know to show these new WebP images instead of the old ones.

    This includes updating image metadata for all featured images and all additional sizes of these. This also means changing the mime type for these images to image/webp. And updating any links to any of these throughout all your post content. The links have to be updated to point to the new WebP. And the same for any images uploaded directly into the Media Library, or inserted into any post or page of any post type.

    To get all of this done at once, use this plugin. This is a quick one-time-use plugin which you can delete right after. Just follow those 6 steps at that link.

You are finally finished converting the data for your WebP images. They should now be visible on your site. Refresh your browser’s cache, and any cache plugins to see the effect of any changes.

Remember, this does nothing for future uploads, and will not convert any WebP images that you upload later. This plugin is only a one-time update for existing images.

See more:

We've One Response

  1. October 13th, 2024 at 3:59 pm

    Just wanted to say thank you. You explain/describe things in a way that I can actually understand. I’ve been blogging on WordPress for years, but I was always too scared to mess with the code, plugins, etc. till I lost most of my traffic and now I’m trying to figure it all out. I just need to understand it first and a lot of articles fail to explain the why before they give you the how but you do both (that made sense in my head, sorry).

    Thrilled that I found you! I feel like I’ve stumbled upon a secret gold mine. Thank you!

    Crystal

Questions and Comments are Welcome

Your email address will not be published. All comments will be moderated.

Please wrap code in "code" bracket tags like this:

[code]

YOUR CODE HERE 

[/code]