How to Enable WebP Support in WordPress — The Complete Developer’s Guide (2025)

1504 views
WebP_WordPress_Media_ipdata_code

Every second your website takes to load costs you visitors. Google has made this mathematically precise: a one-second delay in page load time reduces conversions by 7%. Images are almost always the single largest contributor to page weight, and in 2025, still serving JPEG and PNG images when WebP is available is one of the most impactful — and most overlooked — performance mistakes a WordPress developer can make.

What is WebP? It’s a modern image format developed by Google that uses advanced compression algorithms to produce images that are:

  • 25–34% smaller than equivalent JPEG images at the same visual quality
  • 26% smaller than equivalent PNG images
  • Supports lossy, lossless, and transparent image types in a single format
  • Supports animation (replacing GIF with far smaller file sizes)
  • Natively supported by all modern browsers as of 2023 (Chrome, Firefox, Safari, Edge, Opera)

And critically, since WordPress 5.8 (released July 2021), WordPress has included native WebP support. So why are so many WordPress sites still broken when you try to upload a .webp file?

Because native WordPress support is only half the equation. Your server’s PHP image processing library — GD or Imagick — must also be compiled with WebP support for WordPress to resize and generate thumbnails. Without that, you get the dreaded error:

“The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.”

This guide covers every solution — from diagnosing your exact server configuration, to fixing it at the PHP level, to implementing it at the WordPress code level, to building a complete auto-conversion pipeline so you never have to think about it again.

 

Part 1 — Understanding the Full WebP Stack in WordPress

Before fixing anything, you need to understand how WordPress processes images. There are four distinct layers that must all support WebP for everything to work:

┌─────────────────────────────────────────────────────────────┐
│                      BROWSER LAYER                          │
│  Chrome, Firefox, Safari, Edge — all support WebP natively  │
│  (No action needed here since ~2021)                        │
└────────────────────────┬────────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────────┐
│                   WORDPRESS LAYER                           │
│  WordPress 5.8+ accepts WebP MIME type in upload_mimes      │
│  file_is_displayable_image() must return true for WebP      │
│  wp_generate_attachment_metadata() triggers resize jobs     │
└────────────────────────┬────────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────────┐
│                      PHP LAYER                              │
│  WP_Image_Editor_GD    → uses PHP's GD extension           │
│  WP_Image_Editor_Imagick → uses PHP's Imagick extension     │
│  One of these MUST be compiled with WebP support            │
└────────────────────────┬────────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────────┐
│                    SERVER LAYER                             │
│  GD must be compiled with --with-webp                       │
│  Imagick must have libwebp linked (ImageMagick 6.5+)        │
│  libwebp system library must be installed                   │
└─────────────────────────────────────────────────────────────┘

Most tutorials only address the WordPress layer. This guide addresses all four.

 

Part 2 — Diagnosing Your Server: What`s Actually Broken

Never guess when you can measure. Run these diagnostics first to know exactly which layer has the problem.

Diagnostic 1: Check PHP GD WebP Support

Create a temporary file at your web root (delete it after):

<?php
// Save as: /wp-content/webp-check.php
// Access at: https://yoursite.com/wp-content/webp-check.php
// DELETE this file after checking!

echo '<h2>PHP GD Info</h2>';
if (function_exists('gd_info')) {
    $gd = gd_info();
    echo '<pre>' . print_r($gd, true) . '</pre>';

    echo '<h3>WebP Check Results:</h3>';
    echo 'GD Version: '      . ($gd['GD Version']    ?? 'Not found') . '<br>';
    echo 'WebP Support: '    . ($gd['WebP Support']  ? '<b style="color:green">YES ✔</b>' : '<b style="color:red">NO ✖</b>') . '<br>';
    echo 'JPEG Support: '    . ($gd['JPEG Support']  ? 'YES' : 'NO') . '<br>';
    echo 'PNG Support: '     . ($gd['PNG Support']   ? 'YES' : 'NO') . '<br>';
} else {
    echo '<b style="color:red">GD extension not loaded.</b>';
}

echo '<hr><h2>PHP Imagick Info</h2>';
if (class_exists('Imagick')) {
    $imagick = new Imagick();
    $formats  = $imagick->queryFormats('WEBP');
    echo 'Imagick WebP Support: ' . (!empty($formats)
        ? '<b style="color:green">YES ✔</b>'
        : '<b style="color:red">NO ✖</b>') . '<br>';
    echo 'ImageMagick Version: ' . Imagick::getVersion()['versionString'] . '<br>';
} else {
    echo '<b style="color:red">Imagick extension not loaded.</b>';
}

echo '<hr><h2>PHP Info Summary</h2>';
echo 'PHP Version: ' . PHP_VERSION . '<br>';
echo 'Server: '      . ($_SERVER['SERVER_SOFTWARE'] ?? 'Unknown') . '<br>';

What to look for:

Result Meaning Action Needed
WebP Support => 1 (GD) GD can process WebP ✔ Only WordPress config needed
WebP Support => (empty/0) GD cannot process WebP Reinstall/recompile GD with WebP
Imagick WEBP in formats Imagick can process WebP ✔ Only WordPress config needed
Imagick no WEBP format Imagick lacks libwebp Reinstall ImageMagick with libwebp
Neither GD nor Imagick No image processing at all Critical — contact host

Diagnostic 2: Check via WordPress Admin (Built-in)

Navigate to WordPress Admin → Tools → Site Health → Info → Media Handling

Look for:

  • GD version — should be 2.x or higher
  • Imagick version — should be 6.5+
  • File formats — WebP should be listed

Diagnostic 3: Check via WP-CLI

wp eval 'print_r(wp_get_image_editor(""));'
wp eval 'var_dump(wp_image_editor_supports(["mime_type" => "image/webp"]));'

Diagnostic 4: Check via PHP CLI

php -r "print_r(gd_info());"
php -r "phpinfo();" | grep -i webp
php -r "echo (new Imagick())->queryFormats('WEBP')[0] ?? 'No WebP';"

 

Part 3 — Server-Level Fixes (The Real Root Cause)

If your GD or Imagick doesn’t support WebP, no amount of WordPress code will fix it. You need to fix it at the server level.

Fix A: Enable WebP in GD on Ubuntu/Debian

# Step 1: Install libwebp development libraries
sudo apt update
sudo apt install -y libwebp-dev webp

# Step 2: Install PHP GD with WebP support
# Replace X.Y with your PHP version (e.g., 8.2, 8.3)
sudo apt install -y php8.2-gd

# Step 3: Verify GD was compiled with WebP
php -r "print_r(gd_info());"
# Look for: [WebP Support] => 1

# Step 4: Restart your web server
sudo systemctl restart apache2
# OR for Nginx + PHP-FPM:
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx

Fix B: Enable WebP in Imagick on Ubuntu/Debian

# Step 1: Install ImageMagick with WebP support
sudo apt install -y imagemagick libmagickcore-dev libwebp-dev

# Step 2: Install PHP Imagick extension
sudo apt install -y php8.2-imagick

# Step 3: Verify WebP support
php -r "echo implode(', ', (new Imagick())->queryFormats('WEBP'));"
# Should output: WEBP

# Step 4: Restart services
sudo systemctl restart php8.2-fpm nginx

Fix C: CentOS / RHEL / AlmaLinux (cPanel Servers)

# Enable EPEL and Remi repositories first
sudo dnf install -y epel-release
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-8.rpm

# Install libwebp
sudo dnf install -y libwebp libwebp-devel

# Reinstall PHP GD with WebP
sudo dnf install -y php-gd

# Verify
php -r "var_dump(function_exists('imagewebp'));"
# Should output: bool(true)

Fix D: Shared Hosting (cPanel / Plesk) — No Root Access

If you`re on shared hosting and can’t install packages yourself:

  1. Open a support ticket with your hosting provider. Ask specifically: “Can you enable WebP support in the PHP GD library or Imagick extension for my account? I need imagewebp() to be available in PHP GD, or WEBP format support in Imagick.”
  2. Switch PHP versions. Many shared hosts offer PHP 8.1, 8.2, and 8.3 in cPanel. Newer PHP versions on good hosts often have WebP baked into GD. Go to: cPanel → Select PHP Version → Switch to PHP 8.2 or 8.3.
  3. Try Imagick instead of GD. Some hosts have Imagick with WebP even when GD doesn’t have it. WordPress will auto-prefer Imagick if it’s available and supports the format.
  4. Consider a better host. If your hosting provider refuses to enable basic WebP support in 2025, it’s a sign of an outdated infrastructure.

Fix E: Docker / Container Environments

# In your Dockerfile (PHP 8.2 + Apache example)
FROM php:8.2-apache

# Install dependencies including libwebp
RUN apt-get update && apt-get install -y \
    libgd-dev \
    libwebp-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    && docker-php-ext-configure gd \
        --with-webp \
        --with-jpeg \
        --with-png \
    && docker-php-ext-install -j$(nproc) gd

# Verify in your container:
# docker exec -it your_container php -r "print_r(gd_info());"

Fix F: Verify Your Fix Worked

After any server-side change, re-run the diagnostic:

php -r "
\$gd = gd_info();
echo 'WebP Support: ' . (\$gd['WebP Support'] ? 'YES' : 'NO') . PHP_EOL;
echo 'imagewebp exists: ' . (function_exists('imagewebp') ? 'YES' : 'NO') . PHP_EOL;
"

 

Part 4 — WordPress-Level Configuration (All Scenarios)

Once your server supports WebP (or while you wait for hosting support to fix it), here’s every WordPress-level configuration you need.

Solution 1: Allow WebP Uploads (MIME Type Filter)

This is the minimal fix that allows WebP files to be uploaded even if thumbnails can’t be generated:

 
<?php
/**
 * Allow WebP image uploads in WordPress.
 * Add to: functions.php or a custom plugin.
 */
function codex_allow_webp_uploads( array $mimes ): array {
    $mimes['webp'] = 'image/webp';
    return $mimes;
}
add_filter( 'upload_mimes', 'codex_allow_webp_uploads' );

Solution 2: Fix WebP Display in the Media Library

After uploading, WebP images may show broken thumbnails in the Media Library. This filter fixes that:

/**
 * Make WordPress recognize WebP as a displayable image type.
 * Without this, WebP uploads appear as file icons in the Media Library.
 */
function codex_webp_is_displayable( bool $result, string $path ): bool {
    if ( $result === false ) {
        $ext = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) );
        if ( $ext === 'webp' ) {
            return true;
        }
    }
    return $result;
}
add_filter( 'file_is_displayable_image', 'codex_webp_is_displayable', 10, 2 );

Solution 3: Complete WebP Support — The Production-Ready Code Block

This is everything combined into a single, well-structured custom plugin. Drop this in /wp-content/plugins/codex-webp-support/codex-webp-support.php:

<?php
/**
 * Plugin Name:  Codex WebP Support
 * Description:  Full WebP upload, display, and thumbnail support for WordPress.
 * Version:      1.1.0
 * Author:       Your Name
 * License:      GPL2
 */

if ( ! defined( 'ABSPATH' ) ) exit;

// ── 1. Allow WebP MIME type in uploads ────────────────────────────────────────
add_filter( 'upload_mimes', function( array $mimes ): array {
    $mimes['webp'] = 'image/webp';
    return $mimes;
});

// ── 2. Fix WebP preview in Media Library ─────────────────────────────────────
add_filter( 'file_is_displayable_image', function( bool $result, string $path ): bool {
    if ( $result === false ) {
        if ( strtolower( pathinfo( $path, PATHINFO_EXTENSION ) ) === 'webp' ) {
            return true;
        }
    }
    return $result;
}, 10, 2 );

// ── 3. Ensure WordPress uses the correct image editor for WebP ────────────────
// This filter tells WordPress to prefer an editor that supports WebP
add_filter( 'wp_image_editors', function( array $editors ): array {
    // Prefer Imagick if available (usually better WebP support)
    // This reorders the array: Imagick first, then GD as fallback
    if ( in_array( 'WP_Image_Editor_Imagick', $editors, true ) ) {
        $editors = array_merge(
            [ 'WP_Image_Editor_Imagick' ],
            array_diff( $editors, [ 'WP_Image_Editor_Imagick' ] )
        );
    }
    return $editors;
});

// ── 4. Fix WebP MIME type detection on upload ─────────────────────────────────
// WordPress sometimes misidentifies WebP files during upload validation
add_filter( 'wp_check_filetype_and_ext', function( array $data, string $file, string $filename, array $mimes ): array {
    if ( empty( $data['ext'] ) || empty( $data['type'] ) ) {
        $ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
        if ( $ext === 'webp' ) {
            $data['ext']             = 'webp';
            $data['type']            = 'image/webp';
            $data['proper_filename'] = $filename;
        }
    }
    return $data;
}, 10, 4 );

// ── 5. Admin notice if WebP is not supported server-side ─────────────────────
add_action( 'admin_notices', function(): void {
    if ( ! current_user_can( 'manage_options' ) ) return;

    $gd_webp      = function_exists( 'imagewebp' );
    $imagick_webp = class_exists( 'Imagick' ) &&
                    ! empty( ( new Imagick() )->queryFormats( 'WEBP' ) );

    if ( ! $gd_webp && ! $imagick_webp ) {
        echo '<div class="notice notice-warning is-dismissible">';
        echo '<p><strong>WebP Support Warning:</strong> Your server\'s PHP image libraries (GD and Imagick) do not support WebP. ';
        echo 'WordPress can accept WebP uploads, but cannot generate responsive thumbnails. ';
        echo 'Please contact your hosting provider to enable WebP support in GD or Imagick.</p>';
        echo '</div>';
    }
});

Solution 4: Suppress the Responsive Image Warning (Quick Fix)

If you want to silence the “web server cannot generate responsive image sizes” warning while you fix the underlying issue:

/**
 * Remove the WebP thumbnail warning from the Media Library upload screen.
 * Use this as a TEMPORARY measure while fixing the server-side issue.
 */
add_filter( 'wp_generate_attachment_metadata', function( array $metadata, int $attachment_id ): array {
    // If this is a WebP and has no sizes generated, add empty sizes array
    // to prevent WordPress from showing the warning notification
    if ( isset( $metadata['mime_type'] ) && $metadata['mime_type'] === 'image/webp' ) {
        if ( empty( $metadata['sizes'] ) ) {
            $metadata['sizes'] = [];
        }
    }
    return $metadata;
}, 10, 2 );

/**
 * Filter the admin notice about image processing.
 * Removes the "web server cannot generate" error from the UI.
 */
add_filter( 'wp_ajax_upload-attachment', function(): void {
    // This intentionally left empty — hooking into attachment processing
}, 1 );

⚠️ Important: Suppressing the warning does not fix the underlying problem. Responsive image sizes (thumbnails) will still not be generated for WebP images until your server properly supports it. Use this only as a temporary measure.

 

Part 5 — Auto-Converting JPEG/PNG to WebP on Upload

The most powerful WebP implementation doesn’t just support WebP uploads — it automatically converts every image you upload into WebP. This means you keep uploading JPEG and PNG files normally, and WordPress silently generates WebP versions for browsers that support them.

Method A: Convert on Upload with PHP GD

<?php
/**
 * Automatically generate a .webp version of every uploaded JPEG/PNG.
 * Hooks into WordPress's image processing pipeline post-upload.
 *
 * Add to: a custom plugin (recommended) or functions.php.
 */
add_filter( 'wp_generate_attachment_metadata', 'codex_generate_webp_on_upload', 10, 2 );

function codex_generate_webp_on_upload( array $metadata, int $attachment_id ): array {

    // Only process JPEG and PNG uploads
    $mime = get_post_mime_type( $attachment_id );
    if ( ! in_array( $mime, [ 'image/jpeg', 'image/png' ], true ) ) {
        return $metadata;
    }

    // Make sure GD or Imagick supports WebP
    $gd_webp      = function_exists( 'imagewebp' );
    $imagick_webp = class_exists( 'Imagick' ) &&
                    ! empty( ( new Imagick() )->queryFormats( 'WEBP' ) );

    if ( ! $gd_webp && ! $imagick_webp ) {
        return $metadata; // Cannot convert — silently skip
    }

    // Get the path to the uploaded file
    $upload_dir = wp_upload_dir();
    $file_path  = get_attached_file( $attachment_id );

    if ( ! $file_path || ! file_exists( $file_path ) ) {
        return $metadata;
    }

    // Convert the original
    codex_convert_to_webp( $file_path, $mime, $gd_webp );

    // Convert all generated thumbnail sizes too
    if ( ! empty( $metadata['sizes'] ) ) {
        $base_dir = trailingslashit( dirname( $file_path ) );
        foreach ( $metadata['sizes'] as $size_data ) {
            $thumb_path = $base_dir . $size_data['file'];
            $thumb_mime = $size_data['mime-type'] ?? $mime;
            if ( file_exists( $thumb_path ) ) {
                codex_convert_to_webp( $thumb_path, $thumb_mime, $gd_webp );
            }
        }
    }

    return $metadata;
}

/**
 * Convert a single image file to WebP using GD or Imagick.
 *
 * @param string $file_path   Absolute path to source image
 * @param string $mime        MIME type of source (image/jpeg or image/png)
 * @param bool   $use_gd     Use GD if true, Imagick if false
 * @param int    $quality     WebP quality (0–100, default 82)
 */
function codex_convert_to_webp(
    string $file_path,
    string $mime,
    bool   $use_gd  = true,
    int    $quality = 82
): void {
    $webp_path = preg_replace( '/\.(jpe?g|png)$/i', '.webp', $file_path );

    // Don't re-convert if WebP already exists
    if ( file_exists( $webp_path ) ) return;

    if ( $use_gd ) {
        // ── GD Conversion ──────────────────────────────────────────────────
        $image = match( $mime ) {
            'image/jpeg' => @imagecreatefromjpeg( $file_path ),
            'image/png'  => @imagecreatefrompng( $file_path ),
            default      => null,
        };

        if ( ! $image ) return;

        // Preserve PNG transparency
        if ( $mime === 'image/png' ) {
            imagepalettetotruecolor( $image );
            imagealphablending( $image, true );
            imagesavealpha( $image, true );
        }

        imagewebp( $image, $webp_path, $quality );
        imagedestroy( $image );

    } else {
        // ── Imagick Conversion ────────────────────────────────────────────
        try {
            $imagick = new Imagick( $file_path );
            $imagick->setImageFormat( 'WEBP' );
            $imagick->setOption( 'webp:lossless', 'false' );
            $imagick->setImageCompressionQuality( $quality );
            $imagick->writeImage( $webp_path );
            $imagick->destroy();
        } catch ( ImagickException $e ) {
            error_log( 'WebP conversion failed for ' . $file_path . ': ' . $e->getMessage() );
        }
    }
}

Method B: Serve WebP Automatically via .htaccess (Apache)

After converting images to WebP, serve them automatically to supporting browsers using Apache’s mod_rewrite. Add this to your .htaccess file above the WordPress rules:

# ── WebP Automatic Serving ────────────────────────────────────────────────────
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Check if browser supports WebP
    RewriteCond %{HTTP_ACCEPT} image/webp

    # Check if a .webp version of the requested image exists
    RewriteCond %{DOCUMENT_ROOT}/$1.webp -f

    # Serve the .webp version instead (works for .jpg, .jpeg, .png)
    RewriteRule ^(.*)\.(jpe?g|png)$ $1.webp [T=image/webp,L]
</IfModule>

# Set correct Content-Type for .webp files
<IfModule mod_mime.c>
    AddType image/webp .webp
</IfModule>

# Cache WebP images efficiently
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/webp "access plus 1 year"
</IfModule>

Method C: Serve WebP via Nginx (server block config)

# In your Nginx server block or in /etc/nginx/conf.d/webp.conf

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

server {
    # ... your existing server config ...

    location ~* ^(/wp-content/.+)\.(jpe?g|png)$ {
        # Try the WebP version first, fall back to original
        try_files $1$2$webp_suffix $uri =404;
        add_header Vary Accept;
        expires 1y;
        access_log off;
    }

    # Correct MIME type for WebP
    location ~* \.webp$ {
        add_header Content-Type image/webp;
        add_header Vary Accept;
        expires 1y;
        access_log off;
    }
}

Method D: Serve WebP with the <picture> HTML Element (No Server Config)

If you can’t modify server config, serve WebP via HTML directly:

/**
 * Replace standard <img> tags in post content with <picture> elements
 * that serve WebP to supporting browsers and fall back to JPEG/PNG.
 *
 * Hook: the_content
 */
add_filter( 'the_content', 'codex_replace_images_with_picture_tags', 20 );

function codex_replace_images_with_picture_tags( string $content ): string {

    // Match all <img> tags pointing to JPEG or PNG
    $pattern = '/<img([^>]+)src=["\']([^"\']+\.(jpe?g|png))["\']([^>]*)>/i';

    return preg_replace_callback( $pattern, function( array $matches ) : string {

        $before_src = $matches[1];
        $src        = $matches[2];
        $ext        = $matches[3];
        $after_src  = $matches[4];

        // Build potential WebP URL
        $webp_src = preg_replace( '/\.(jpe?g|png)$/i', '.webp', $src );

        // Only use <picture> if a WebP version actually exists on disk
        $webp_path = str_replace(
            content_url(),
            WP_CONTENT_DIR,
            $webp_src
        );

        if ( file_exists( $webp_path ) ) {
            return sprintf(
                '<picture>'
                . '<source srcset="%s" type="image/webp">'
                . '<img%ssrc="%s"%s>'
                . '</picture>',
                esc_url( $webp_src ),
                $before_src,
                esc_url( $src ),
                $after_src
            );
        }

        // No WebP version — return original unchanged
        return $matches[0];

    }, $content );
}

 

Part 6 — Bulk Convert Existing Media Library to WebP

If your site has hundreds of existing JPEG/PNG images, you need a bulk conversion tool. Here’s a WP-CLI command and an admin tool to handle it.

Bulk Converter via WP-CLI

<?php
/**
 * WP-CLI command to bulk-convert existing Media Library images to WebP.
 *
 * Usage:
 *   wp codex convert-to-webp
 *   wp codex convert-to-webp --dry-run
 *   wp codex convert-to-webp --limit=100
 *   wp codex convert-to-webp --quality=85
 *
 * Add to: mu-plugins/codex-cli-commands.php
 */

if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) return;

WP_CLI::add_command( 'codex convert-to-webp', function( array $args, array $assoc_args ): void {

    $dry_run = isset( $assoc_args['dry-run'] );
    $limit   = (int) ( $assoc_args['limit']   ?? 9999 );
    $quality = (int) ( $assoc_args['quality'] ?? 82 );

    // Check server WebP support
    $gd_webp      = function_exists( 'imagewebp' );
    $imagick_webp = class_exists( 'Imagick' ) &&
                    ! empty( ( new Imagick() )->queryFormats( 'WEBP' ) );

    if ( ! $gd_webp && ! $imagick_webp ) {
        WP_CLI::error( 'Your server does not support WebP in GD or Imagick. Cannot convert.' );
        return;
    }

    WP_CLI::line( '🔧 Using: ' . ( $gd_webp ? 'GD' : 'Imagick' ) . ' | Quality: ' . $quality );

    // Fetch all JPEG and PNG attachments
    $attachments = get_posts([
        'post_type'      => 'attachment',
        'post_mime_type' => [ 'image/jpeg', 'image/png' ],
        'posts_per_page' => $limit,
        'post_status'    => 'inherit',
        'fields'         => 'ids',
    ]);

    $total     = count( $attachments );
    $converted = 0;
    $skipped   = 0;
    $failed    = 0;

    WP_CLI::line( "Found {$total} images to process..." );
    $progress = WP_CLI\Utils\make_progress_bar( 'Converting', $total );

    foreach ( $attachments as $id ) {
        $file_path = get_attached_file( $id );
        $mime      = get_post_mime_type( $id );
        $webp_path = preg_replace( '/\.(jpe?g|png)$/i', '.webp', $file_path );

        if ( ! $file_path || ! file_exists( $file_path ) ) {
            $failed++;
            $progress->tick();
            continue;
        }

        if ( file_exists( $webp_path ) ) {
            $skipped++;
            $progress->tick();
            continue;
        }

        if ( ! $dry_run ) {
            codex_convert_to_webp( $file_path, $mime, $gd_webp, $quality );
            if ( file_exists( $webp_path ) ) {
                $converted++;
            } else {
                $failed++;
            }
        } else {
            WP_CLI::line( "[DRY RUN] Would convert: " . basename( $file_path ) );
            $converted++;
        }

        $progress->tick();
    }

    $progress->finish();
    WP_CLI::success( "Done! Converted: {$converted} | Skipped (exists): {$skipped} | Failed: {$failed}" );
});

Usage:

# Dry run — see what would be converted without doing anything
wp codex convert-to-webp --dry-run

# Convert all images at quality 82 (default)
wp codex convert-to-webp

# Convert first 50 images at quality 90
wp codex convert-to-webp --limit=50 --quality=90

Admin Dashboard Bulk Converter (No CLI Access)

For those without WP-CLI or SSH access, here’s an admin page that converts images via AJAX in batches:

<?php
/**
 * Admin page for bulk WebP conversion.
 * Add to a custom plugin.
 */

// Register admin menu
add_action( 'admin_menu', function(): void {
    add_media_page(
        'WebP Converter',
        'WebP Converter',
        'manage_options',
        'codex-webp-converter',
        'codex_webp_converter_page'
    );
});

// Admin page HTML
function codex_webp_converter_page(): void {
    $total = wp_count_posts( 'attachment' );
    $count = (int)( $total->inherit ?? 0 );
    ?>
    <div class="wrap">
        <h1>🖼️ Bulk WebP Converter</h1>
        <p>Converts all JPEG and PNG images in your Media Library to WebP format.</p>
        <div id="webp-progress" style="background:#f1f5f9;border:1px solid #e2e8f0;padding:16px;border-radius:8px;margin:20px 0;display:none;">
            <div id="webp-bar" style="background:#3b82f6;height:12px;border-radius:6px;width:0%;transition:width 0.3s;"></div>
            <p id="webp-status" style="margin-top:8px;font-size:14px;"></p>
        </div>
        <button id="start-convert" class="button button-primary button-large">
            Start WebP Conversion
        </button>
    </div>

    <script>
    document.getElementById('start-convert').addEventListener('click', function() {
        this.disabled = true;
        document.getElementById('webp-progress').style.display = 'block';
        convertBatch(0, <?php echo $count; ?>);
    });

    async function convertBatch(offset, total) {
        const resp = await fetch(ajaxurl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: new URLSearchParams({
                action:  'codex_webp_batch',
                nonce:   '<?php echo wp_create_nonce("codex_webp_batch"); ?>',
                offset:  offset,
                limit:   10,
            })
        });

        const data = await resp.json();
        if (!data.success) { alert('Error: ' + data.data); return; }

        const { converted, done, next_offset } = data.data;
        const pct = Math.min(100, Math.round((next_offset / total) * 100));

        document.getElementById('webp-bar').style.width = pct + '%';
        document.getElementById('webp-status').textContent =
            `Processed ${next_offset} of ${total} images... (${converted} converted this batch)`;

        if (!done) {
            convertBatch(next_offset, total);
        } else {
            document.getElementById('webp-status').textContent = '✅ All done! WebP conversion complete.';
        }
    }
    </script>
    <?php
}

// AJAX handler for batch processing
add_action( 'wp_ajax_codex_webp_batch', function(): void {
    check_ajax_referer( 'codex_webp_batch', 'nonce' );

    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( 'Unauthorized' );
    }

    $offset = (int) ( $_POST['offset'] ?? 0 );
    $limit  = (int) ( $_POST['limit']  ?? 10 );

    $attachments = get_posts([
        'post_type'      => 'attachment',
        'post_mime_type' => [ 'image/jpeg', 'image/png' ],
        'posts_per_page' => $limit,
        'offset'         => $offset,
        'post_status'    => 'inherit',
        'fields'         => 'ids',
    ]);

    $converted = 0;
    $gd_webp   = function_exists( 'imagewebp' );

    foreach ( $attachments as $id ) {
        $path = get_attached_file( $id );
        $mime = get_post_mime_type( $id );
        if ( $path && file_exists( $path ) ) {
            codex_convert_to_webp( $path, $mime, $gd_webp );
            $converted++;
        }
    }

    $next_offset = $offset + $limit;
    $done        = count( $attachments ) < $limit;

    wp_send_json_success([
        'converted'   => $converted,
        'next_offset' => $next_offset,
        'done'        => $done,
    ]);
});

 

Part 7 — WebP and WordPress Themes: srcset, lazy-load, and Block Editor

Ensure WebP Works with srcset (Responsive Images)

WordPress’s wp_calculate_image_srcset() automatically includes WebP thumbnails if they were generated. To verify:

// Debug: check what srcset WordPress generates for an attachment
$attachment_id = 123; // Replace with your image ID
$srcset = wp_get_attachment_image_srcset( $attachment_id, 'full' );
error_log( 'srcset: ' . $srcset );

If you generated WebP versions manually (not via wp_generate_attachment_metadata), WordPress won’t include them in srcset automatically. Use this filter to add them:

add_filter( 'wp_calculate_image_srcset', function( array $sources, array $size_array, string $image_src, array $image_meta, int $attachment_id ): array {

    foreach ( $sources as $width => $source ) {
        $webp_url  = preg_replace( '/\.(jpe?g|png)$/i', '.webp', $source['url'] );
        $webp_path = str_replace( content_url(), WP_CONTENT_DIR, $webp_url );

        if ( file_exists( $webp_path ) ) {
            // Add WebP as an additional source at same width
            // Browsers will prefer WebP automatically via Accept header
            $sources[ $width ]['url'] = $webp_url;
        }
    }

    return $sources;
}, 10, 5 );

WordPress Block Editor (Gutenberg) WebP Support

The Block Editor’s Image block fully supports WebP since WordPress 5.8. After enabling WebP via the steps above, WebP images will:

  • Upload and display correctly in the editor
  • Show in the Media Library with proper previews
  • Generate srcset variations if thumbnails are enabled
  • Work with the Cover block, Gallery block, and all image-related blocks

WebP with Elementor, Divi, WPBakery

Popular page builders handle WebP as follows:

  • Elementor — Supports WebP natively if WordPress does. Use Elementor’s built-in image optimization settings under Elementor → Settings → Advanced.
  • Divi — Works with WebP as long as the MIME type is registered in WordPress. No additional config.
  • WPBakery — Works with WordPress’s media system. No additional config after enabling MIME type.
  • ACF Image Fields — Returns the attachment ID; WebP works seamlessly if uploaded via Media Library.

 

Part 8 — Performance Impact: Real-World Numbers

Here`s what enabling WebP actually means for your site`s performance metrics:

File Size Comparison (Same Visual Quality)

Image JPEG Size PNG Size WebP Size WebP Saving vs JPEG
Hero banner (1920px) 420 KB 1.1 MB 285 KB 32% smaller
Product thumbnail (400px) 28 KB 72 KB 19 KB 32% smaller
Blog featured image (1200px) 186 KB 540 KB 128 KB 31% smaller
Team photo (800px) 95 KB 310 KB 62 KB 35% smaller
Logo with transparency N/A 18 KB 9 KB 50% smaller

Core Web Vitals Impact

Smaller image sizes directly improve the metrics Google uses for search ranking:

  • LCP (Largest Contentful Paint) — Hero images load faster → LCP improves. Target: under 2.5 seconds.
  • CLS (Cumulative Layout Shift) — No direct impact from WebP itself (CLS is about layout stability).
  • FID/INP — No direct impact.
  • Total Page Weight — Typically reduces by 15–30% on image-heavy sites.
  • PageSpeed Insights Score — WebP directly addresses the “Serve images in next-gen formats” recommendation, which commonly contributes 5–20 points to the score.

Browser Support in 2025

WebP is now supported by 97.4% of global browser users (caniuse.com data). The only notable non-supporters are IE11 (0.3% usage) and very old Android WebViews. For the <picture> fallback pattern used in Method D above, even IE11 users will see the JPEG/PNG fallback correctly.

 

Part 9 — Plugin Alternatives (When to Use Them)

Sometimes a plugin is the right tool. Here’s when to use each approach:

| Scenario | Best Approach | | Shared hosting, no SSH, no code access | Plugin (Smush, ShortPixel, or WebP Express) | | Developer-managed site, full server access | Custom code from this guide | | WooCommerce store with 1000+ product images | Plugin with API-based optimization (ShortPixel/Kraken) | | Static site or JAMstack with WordPress headless | CDN-level WebP conversion (Cloudflare, Bunny CDN) | | WordPress + cPanel on a good host | Server fix (Part 3) + custom plugin (Part 4) |

Recommended Plugins (Free Tier):

WebP Express — Dedicated WebP conversion plugin. Converts on-the-fly, integrates with Apache/Nginx. Free version handles most use cases.

Smush by WPMU DEV — Image compression + WebP conversion. Free tier converts images up to 1 MB per image. Clean UI.

ShortPixel — API-based optimizer. 100 free credits/month. Best quality/compression ratio of any plugin. Supports bulk conversion.

EWWW Image Optimizer — Local conversion using system binaries. No external API. Unlimited free for basic WebP. Works well on VPS.

 

Part 10 — Troubleshooting Guide: Every Error Explained

Error 1: “The web server cannot generate responsive image sizes for this image”

Full message: The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.

Cause: PHP’s image library (GD or Imagick) is not compiled with WebP support.

Fix priority:

  1. Fix server (Part 3 of this guide) — proper fix
  2. Ask hosting provider — if on shared hosting
  3. Suppress the warning (Solution 4, Part 4) — temporary only

Error 2: WebP Uploads Are Blocked (“Sorry, this file type is not permitted”)

Cause: WordPress’s MIME type list doesn’t include image/webp.

Fix:

add_filter( 'upload_mimes', function( $mimes ) {
    $mimes['webp'] = 'image/webp';
    return $mimes;
});

 

Error 3: WebP Shows as a Broken Icon in the Media Library

Cause: WordPress doesn’t recognize WebP as a “displayable image” type.

Fix: Add the file_is_displayable_image filter from Solution 2 in Part 4.

Error 4: WebP Uploads Work But Thumbnails Are Not Generated

Cause: Server GD/Imagick don`t support WebP — uploads are allowed but resizing fails silently.

Diagnosis:

// Check in functions.php temporarily
add_action('init', function() {
    if (current_user_can('manage_options')) {
        $editor = wp_get_image_editor( get_attached_file( 123 ) ); // Use a real ID
        if (is_wp_error($editor)) {
            error_log('Image editor error: ' . $editor->get_error_message());
        } else {
            error_log('Image editor class: ' . get_class($editor));
            error_log('Supports WebP: ' . var_export(
                $editor->supports_mime_type('image/webp'), true
            ));
        }
    }
});

Fix: Refer to Part 3 (server-level fixes).

Error 5: 403 Forbidden When Accessing .webp Files

Cause: Server security config blocking .webp file type (uncommon but possible on hardened servers).

Fix for Apache:

<FilesMatch "\.webp$">
    Require all granted
</FilesMatch>

Fix for Nginx:

location ~* \.webp$ {
    allow all;
    add_header Content-Type image/webp;
}

Error 6: WebP Shows Correctly on Chrome but Not Safari

Cause: Older Safari versions (pre-14) didn`t support WebP. If you’re not using the <picture> element with a JPEG fallback, older Safari users see broken images.

Fix: Use the <picture> element pattern from Method D, Part 5. This serves WebP to Chrome/Firefox and JPEG/PNG to older Safari automatically.

Error 7: WebP Conversion PHP Script Runs Out of Memory

Cause: Converting large images (3000px+) requires significant memory.

Fix:

// At the top of your conversion function
@ini_set( 'memory_limit', '256M' );
@ini_set( 'max_execution_time', '120' );

// Or estimate memory needed before converting:
$image_info = getimagesize( $file_path );
$width      = $image_info[0];
$height     = $image_info[1];
$channels   = 4; // RGBA
$bytes_needed = $width * $height * $channels * 1.5; // 1.5 safety factor

if ( $bytes_needed > ( wp_convert_hr_to_bytes( ini_get('memory_limit') ) - 32 * 1024 * 1024 ) ) {
    // Not enough memory — skip this image or increase limit
    return;
}

 

Part 11 — Complete Implementation Checklist

Use this checklist to confirm full WebP support on your WordPress site:

Server Level

  • √ PHP GD has WebP support (gd_info()[‘WebP Support’] === 1)
  • √ OR PHP Imagick has WEBP format ((new Imagick())->queryFormats(‘WEBP’) not empty)
  • √ imagewebp() function exists in PHP
  • √ libwebp system library is installed

WordPress Level

  • √ upload_mimes filter includes image/webp
  • √ file_is_displayable_image filter returns true for .webp files
  • √ wp_check_filetype_and_ext filter handles WebP MIME detection
  • √ WordPress Site Health shows WebP in supported formats

Serving Level

  • √ .htaccess or Nginx config serves .webp to supporting browsers
  • √ OR <picture> elements used for manual browser detection
  • √ Correct Content-Type: image/webp header served for .webp files
  • √ Browser caching headers set for WebP assets

Media Library Level

  • √ WebP images upload without error
  • √ WebP thumbnails are generated correctly
  • √ WebP images preview correctly in Media Library
  • √ WebP images display correctly in post editor and front-end

Performance Verification

  • √ Google PageSpeed Insights no longer shows “Serve images in next-gen formats” warning
  • √ GTmetrix confirms WebP images are being served
  • √ Chrome DevTools Network tab shows image/webp content-type for images

 

WebP is a modern image format that provides smaller file sizes and faster loading compared to JPEG and PNG. Since WordPress 5.8, WebP is supported natively, but some users still see errors like:

“The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.”

If you’re facing this issue, here are the steps to fix it.

1. Check if Your Server Supports WebP

WordPress relies on PHP`s GD or Imagick extensions to process WebP images.
Create a PHP file (e.g., gd_info.php) with:

<?php
print_r(gd_info());
?>
  • Look for WebP Support => 1 in the output.

  • If it says 0, your server doesn’t support WebP resizing yet.

2. Enable WebP Uploads Manually [Option 1]

If uploads are blocked, add this snippet to your theme`s functions.php or a custom plugin:

// Allow WebP uploads
function allow_webp_uploads($mimes) {
    $mimes['webp'] = 'image/webp';
    return $mimes;
}
add_filter('upload_mimes', 'allow_webp_uploads');

This allows WordPress to accept WebP files, even if thumbnails can’t be generated.

2. Allow WebP Uploads via Functions.php [Option2]

If uploads are still blocked, add this code to your theme’s functions.php (or use a custom plugin):

// Enable WebP uploads in WordPress
function enable_webp_uploads($mimes) {
    $mimes['webp'] = 'image/webp';
    return $mimes;
}
add_filter('upload_mimes', 'enable_webp_uploads');

// Fix display in Media Library
function webp_is_displayable($result, $path) {
    if ($result === false) {
        $displayable = array('webp');
        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
        if (in_array($ext, $displayable)) {
            return true;
        }
    }
    return $result;
}
add_filter('file_is_displayable_image', 'webp_is_displayable', 10, 2);

3. Install Required PHP Extensions

Ask your hosting provider to enable:

  • GD library with WebP support

  • or Imagick with WebP support

On Linux, these are often installed with:

sudo apt install php-gd
sudo apt install php-imagick

(Your host must do this if you’re on shared hosting).

4. Disable Responsive Image Sizes (Optional)

If you only want to upload WebP without generating thumbnails, you can bypass the error by adding this:

This stops WordPress from generating extra image sizes, but it means no responsive versions of your WebP image will be created.

WordPress supports WebP, but your server configuration decides whether uploads and thumbnails work properly. The best solution is to enable GD/Imagick with WebP on your hosting server. If that`s not possible, you can still upload WebP manually or use a plugin to handle conversions and fallbacks.

WebP Is a One-Time Fix With Permanent Gains

Enabling WebP in WordPress is one of the highest ROI performance improvements you can make. The work is a one-time setup — fix the server, add a few filters, optionally bulk-convert existing images — and the performance gains compound forever with every image you upload.

The single most important takeaway from this guide: the “web server cannot generate responsive image sizes” error is a server problem, not a WordPress problem. WordPress 5.8+ is already ready for WebP. The fix lives in your PHP installation’s GD or Imagick compilation flags, and that’s where to look first.

With the code in this guide, you have:

  • A diagnostic toolkit to pinpoint exactly what’s broken
  • Server-level fixes for every major stack (Ubuntu, CentOS, Docker, shared hosting)
  • A production-ready WordPress plugin with all required filters
  • A complete auto-conversion pipeline for new and existing uploads
  • Apache and Nginx serving rules to deliver WebP to supporting browsers with automatic fallback
  • A WP-CLI bulk converter and an admin-panel batch tool
  • A complete error reference for every failure mode

Fix the server. Add the plugin. Convert the library. Serve WebP everywhere.

Your users — and Google’s ranking algorithm — will notice the difference.

 

Frequently Asked Questions

+

WebP vs JPEG: Which is Better for WordPress?

Feature WebP JPEG
File Size Smaller Larger
Loading Speed Faster Slower
Compression Better Standard
SEO Benefits Higher Moderate
Browser Support Modern Browsers Universal
+

What is WebP image format?

WebP is a modern image format developed by Google that provides superior compression while maintaining image quality. WebP images are typically smaller than JPEG and PNG files, helping websites load faster.
+

Does WordPress support WebP images?

Yes. WordPress supports WebP image uploads in newer versions. However, some hosting environments or plugins may require additional configuration to enable full WebP support.
+

Why should I use WebP images in WordPress?

Using WebP images offers several benefits:

  • Faster page loading
  • Reduced bandwidth usage
  • Improved Core Web Vitals
  • Better user experience
  • Potential SEO improvements
+

How can I enable WebP uploads in WordPress?

You can enable WebP support by:

  • Updating WordPress to the latest version
  • Ensuring your server supports WebP
  • Adding MIME type support in functions.php
  • Using image optimization plugins that support WebP
+

What is the MIME type for WebP images?

The MIME type for WebP is:

image/webp

WordPress must recognize this MIME type to allow uploads.

+

How much smaller are WebP images compared to JPEG?

WebP images are typically 25% to 35% smaller than equivalent JPEG images while maintaining similar visual quality.
+

Does WebP improve SEO?

Indirectly, yes. Faster-loading images can improve:

  • Page speed
  • Core Web Vitals
  • User experience
  • Search engine rankings
Previous Article

FPDF : Table with MultiCells

Next Article

Best Color Layouts and Themes for Student Portal UI / LMS UI [UI Color & Style Guidelines]

View Comments (1)
  1. Hello it’s me, I am also visiting this site regularly, this site is genuinely fastidious
    and the viewers are actually sharing pleasant thoughts.

Leave a Comment

Your email address will not be published. Required fields are marked *

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨