Your site loads slow, you check PageSpeed Insights, and Google says: “Serve images in next-gen formats like WebP.”
Sounds familiar? Many WordPress users stuck here. You don’t want to add another heavy plugin, but you also don’t know how to make WordPress convert images to WebP by itself.
I had the same issue, and I fix it with a simple PHP snippet. It’s lightweight, no plugin needed, and works on new uploads right away. Let me share it with you.
TL;DR – Jump straight to the code snippet ⬇️
Why Switch To WebP in WordPress
If you care about site speed (and SEO), you should not rely only on JPG or PNG. Here’s why I recommend WebP to clients:
- Browser support is ready – Chrome, Edge, Firefox, even Safari support WebP now.
- File size smaller – On average 30–50% smaller than JPG or PNG. I’ve seen 2MB PNG shrink to under 1MB WebP.
- Better SEO performance – Google push fast websites higher, and images are one of the easiest way to speed up.
- Google itself recommend – PageSpeed Insights literally tell you to convert images to WebP.
In one project, after converting images to WebP, site load time drop almost 1 second. No caching trick, no CDN, just image change.
Free PHP Code To Convert Images To WebP in WordPress
Here’s the snippet I use (originally by Mark Harris, modified a bit by me). It will convert new uploads (JPG and PNG) to WebP automatically.
What I changed:
- Adds a
-1
suffix if you upload the same file twice. - Skips GIFs so animations don’t break.
<?php
/**
* Convert Uploaded Images to WebP Format
*
* This snippet converts uploaded images (JPEG & PNG) to WebP format
* automatically in WordPress. Ideal for use in a theme's functions.php file,
* or with plugins like Code Snippets or WPCodeBox.
*
* @package WordPress_Custom_Functions
* @author Mark Harris
* @link www.christchurchwebsolutions.co.uk
*
* Modification:
* - Added a counter to the filename for duplicate uploads and remove .gif
* - Excludes already uploaded WebP images from conversion.
* - Checks for duplicate filenames across the entire media library, not just the current folder.
* - Optimized for performance.
*
* @author Adit MB
* @link https://webdivo.com
*
* Usage Instructions:
* - Add this snippet to your theme's functions.php file, or add it as a new
* snippet in Code Snippets or WPCodeBox.
* - The snippet hooks into WordPress's image upload process and converts
* uploaded images to the WebP format.
*
* Optional Configuration:
* - By default, the original image file is deleted after conversion to WebP.
* If you prefer to keep the original image file, simply comment out or remove
* the line '@unlink( $file_path );' in the wpturbo_handle_upload_convert_to_webp function.
* This will preserve the original uploaded image file alongside the WebP version.
*/
add_filter('wp_handle_upload', 'wpturbo_handle_upload_convert_to_webp');
function wpturbo_handle_upload_convert_to_webp($upload)
{
// Determine if the uploaded image is a type we can convert (JPG, PNG)
$is_convertible = in_array($upload['type'], ['image/jpeg', 'image/png'], true);
// Determine if the uploaded image is already a WebP.
$is_webp = ($upload['type'] === 'image/webp');
// If the file type is not a convertible image or a WebP, do nothing.
if (!$is_convertible && !$is_webp) {
return $upload;
}
// Get file path information.
$file_path = $upload['file'];
$file_info = pathinfo($file_path);
$dirname = $file_info['dirname'];
$filename = $file_info['filename']; // Filename without extension.
// For convertible types, the target is .webp. For existing WebP, it's the original extension.
$target_extension = $is_convertible ? '.webp' : '.' . $file_info['extension'];
// --- Global Duplicate Filename Check ---
global $wpdb;
$new_filename_base = $filename;
$counter = 1;
$new_filename_with_ext = $new_filename_base . $target_extension;
// Loop to find a unique name across the entire media library.
// This is more reliable than file_exists() as it checks the database for the filename.
while ($wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_key = '_wp_attached_file' AND meta_value LIKE %s",
'%' . $wpdb->esc_like($new_filename_with_ext)
)) > 0) {
$new_filename_base = $filename . '-' . $counter;
$new_filename_with_ext = $new_filename_base . $target_extension;
$counter++;
}
// This is the unique path for our final file.
$new_file_path = $dirname . '/' . $new_filename_with_ext;
// --- Handle Conversion for JPG/PNG ---
if ($is_convertible) {
// Check if ImageMagick or GD is available.
if (!extension_loaded('imagick') && !extension_loaded('gd')) {
return $upload; // Cannot convert, return original.
}
$image_editor = wp_get_image_editor($file_path);
if (is_wp_error($image_editor)) {
return $upload; // Editor error, return original.
}
// Attempt to save the image in WebP format to the unique path.
$saved_image = $image_editor->save($new_file_path, 'image/webp');
if (!is_wp_error($saved_image) && file_exists($saved_image['path'])) {
// Success: replace the uploaded image with the WebP image.
$upload['file'] = $saved_image['path'];
$upload['url'] = str_replace(basename($upload['url']), basename($saved_image['path']), $upload['url']);
$upload['type'] = 'image/webp';
// Optionally remove the original image.
@unlink($file_path);
}
// If saving fails, we fall through and return the original $upload array.
// --- Handle Renaming for duplicate WebP ---
} elseif ($is_webp) {
// If the unique path is different from the original path, a duplicate was found.
if ($new_file_path !== $file_path) {
// Rename the physical file.
if (rename($file_path, $new_file_path)) {
// Success: update the upload array with the new path and URL.
$upload['file'] = $new_file_path;
$upload['url'] = str_replace(basename($upload['url']), basename($new_file_path), $upload['url']);
}
// If rename fails, we fall through and return the original $upload.
}
}
return $upload;
}
How To Add This Snippet
It’s simple, just follow step by step:
- Check hosting support – Make sure GD or Imagick extension enabled (most hosting already have).
- Add the snippet – Paste into
functions.php
or use code snippet plugin (Fluent Snippet, WPCodeBox are good). - Watch PHP tags – If your file already start with
<?php
, don’t add again. - Enable – Save or activate the snippet.
Done. Now WordPress will automatically convert images to WebP when you upload them.
Important: This only affect new uploads, not old ones.
Real Example: File Size Comparison
I tested with two same PNG images:
- Without snippet: 1 MB
- With snippet (converted to WebP): 34 KB
These test done using image generated by AI. Your result may vary depending on the color complexity. But from my personal experience it will save 50-80% easy.

What If You Want To Keep Original File
By default, the snippet delete the original JPG/PNG after convert. I recommend this, because it saves space.
But if you want to keep the original:
- Comment out or remove this line in the code:
@unlink( $file_path );
- The file won’t show inside Media Library, but it still stored in
/wp-content/uploads/
.
WebP vs AVIF: Which One Better?
Some people ask me: why not use AVIF? It’s smaller, right? True, but I still prefer WebP in WordPress projects:
- Better browser support – WebP works almost everywhere, AVIF still not stable.
- Works with plugins – Most image optimization and WordPress tools handle WebP smoothly.
- Quality safe – AVIF sometimes show artifact, while WebP balance quality and size.
For now, WebP is safer and more practical choice if you want stable result and SEO benefit.
My Final Thoughts
If you want to convert images to WebP in WordPress without extra plugin, this PHP snippet is best option.
- It’s free, just copy-paste.
- Works with JPG and PNG uploads.
- Reduce size 30–50% instantly.
- Help speed up your site and improve SEO.
Try it, then run your PageSpeed Insights again. You will see the score better and site load faster.
This is one of the easiest optimization you can do. And if you want more help with WordPress speed and SEO, that’s what I do at Webdivo.