2026年6月8日

WordPress 图片压缩提速完整指南:Converter for Media 与 Cloudflare 缓存配置

图片过大是 WordPress 网站加载慢的最常见原因之一。通过将 JPG、PNG 转换为 WebP 或 AVIF 格式,通常可以减少 30%–70% 的图片体积,从而显著提升页面加载速度、改善 Core Web Vitals 评分,并降低用户跳出率。

本文以 Converter for Media(原 WebP Converter for Media)为例,讲解如何在 Nginx 服务器环境下完成 WordPress 图片压缩与格式转换,并正确配合 Cloudflare 缓存,避免“图片格式错乱”或“插件检测不通过”的问题。

如果你使用 WP Panel 管理站点,文中会说明在哪一层面板入口写入 Nginx 规则。

参考文档:


一、为什么要做 WordPress 图片压缩与格式转换?

  • WebP 比 JPEG 小约 25%–35%,AVIF 甚至比 WebP 再小 20%–50%。
  • 图片体积下降直接影响 LCP(最大内容绘制),是 Google Core Web Vitals 的重要指标。
  • 加载速度越快,用户体验越好,SEO 排名和转化率也越容易提升。
  • 使用 Converter for Media 这类插件,可以在不修改图片 URL 的情况下,自动根据浏览器支持返回 WebP 或 AVIF,兼容旧浏览器。

二、Nginx 环境下需要手动添加什么规则?

Apache 服务器通常可以通过 .htaccess 自动生效,但 Nginx 不支持 .htaccess,当你启用插件后,插件界面会提示:

服务器配置错误

对于Nginx服务器,请联系您的主机技术支持,以使插件正常运行。您的服务器需要额外的配置,但您的主机技术支持将为您处理。

因此,我们需要手动去给服务器添加Nginx配置才能让插件正常工作。

2.1 在 WP Panel 中写入 Nginx 规则

登录 WP Panel 后,按以下路径进入:

网站管理 -> 网站详情 -> Nginx 自定义配置 -> Server 级配置

将下方的官方规则粘贴进去:

# BEGIN Converter for Media
set $ext_avif ".avif";
if ($http_accept !~* "image/avif") {
    set $ext_avif "";
}

set $ext_webp ".webp";
if ($http_accept !~* "image/webp") {
    set $ext_webp "";
}

location ~* ^/wp-content/(?<path>.+)\.(?<ext>jpe?g|png|gif|webp)$ {
    add_header Vary Accept;
    add_header Cache-Control "private";
    expires 365d;
    try_files
        /wp-content/uploads-webpc/$path.$ext$ext_avif
        /wp-content/uploads-webpc/$path.$ext$ext_webp
        $uri =404;
}
# END Converter for Media

保存后,WP Panel 会自动执行 Nginx 语法检查。配置合法才会真正生效,面板会阻止错误的配置写入,避免 Nginx 损坏。

宝塔面板用户?参考:宝塔面板修改nginx配置支持Converter for Media插件

2.2 为什么必须放在 Server 级配置?

Converter for Media 的规则需要插入到当前站点的 server { ... } 块中,并且要早于其他图片静态资源 location。WP Panel 的 Server 级配置正好会被插入到站点 Nginx 配置的靠前位置,适合放这类插件规则。


三、插件提示“HTTP 请求被缓存”是什么意思?

您的服务器似乎使用缓存进行HTTP请求。

规则已经添加,但插件后台仍可能提示:

您的服务器似乎使用缓存进行 HTTP 请求。不是每次加载图像时都会执行来自 .htaccess 文件或 Nginx 配置的规则,而是执行来自缓存的最后一次重定向。

这通常不是 Nginx 规则写错,而是 CDN 或缓存层没有正确处理这两个响应头:

Vary: Accept
Cache-Control: private

Converter for Media 会根据浏览器请求头里的 Accept 判断返回 WebP 还是 AVIF。同一个 JPG/PNG URL,支持的浏览器可能拿到 WebP/AVIF,不支持的浏览器则拿到原图。如果 CDN 只按 URL 缓存、不按 Accept 区分,就会出现:

  • 支持 WebP 的浏览器拿到 JPG;
  • 不支持 WebP 的浏览器拿到 WebP;
  • 插件一直提示缓存异常;
  • Cloudflare 响应头显示 CF-Cache-Status: HIT,但请求根本没有回到源站 Nginx。

四、Cloudflare 免费版如何处理?

要让 CDN 正确缓存这种“同一 URL 不同格式”的动态图片响应,CDN 必须支持按 Accept 头区分缓存。Cloudflare 的这项能力叫做 Vary for Images。

根据 Cloudflare 官方文档,Vary for Images 仅支持 Pro、Business、Enterprise 套餐,免费版不支持。

因此:

  • Cloudflare Free 用户:不建议缓存 /wp-content/uploads/* 下的转换图片,应让请求回源,由 Nginx 按 Accept 返回正确格式。
  • Cloudflare Pro / Business / Enterprise 用户:可以按照 Converter for Media 官方文档配置 Cloudflare API Token 和 Zone ID,让插件自动完成 Cloudflare 图片缓存配置。
  • 如果 Free 套餐强行缓存图片,可能导致插件提示 HTTP 请求缓存异常,或者不同浏览器拿到不匹配的图片格式。

换句话说,Cloudflare 免费版不是“不需要配置”,而是“不支持按 Accept 区分图片缓存的能力”。免费版用户如果想保证插件检测通过和图片格式兼容,应该绕过这类动态图片缓存。

但是问题来了,如果缓存规则配置绕过了uploads目录下的资源缓存,网站最大的流量消耗资源不就没走CDN了吗?所以,我们可以换另外一种形式来实现网页图片依然走CDN流量。


五、Cloudflare免费版与 Converter for Media 兼容处理

第四点已经说了,因为免费版的Cloudflare不支持自动按 Accept 头区分图片缓存,所以就算你用插件把所有图片都转换为了webp格式,但是在CDN请求时默认忽略你服务器的图片自动判断规则,默认直接走原图,不会管你是否存在webp。

这个时候我们可以借助HTML5 的< picture >标签来实现图片输出webp和原图两种格式。

将下面的代码复制粘贴到你网站主题函数文件functions.php里面。

/**
 * WordPress + Cloudflare Free + Converter for Media
 * 仅在 WebP 文件真实存在时,将 jpg/png 图片包装为 picture。
 * 支持 uploads 目录 + 当前主题目录图片。
 */

function nbj_get_webp_info($src, $uploads) {
    $src_raw  = html_entity_decode($src);
    $src_path = parse_url(esc_url_raw($src_raw), PHP_URL_PATH);

    if (!$src_path || strpos($src_path, '..') !== false) {
        return false;
    }

    /**
     * 1. 处理媒体库 uploads 图片
     */
    $uploads_baseurl = $uploads['baseurl'];
    $uploads_basedir = $uploads['basedir'];

    $uploads_base_path = parse_url(esc_url_raw($uploads_baseurl), PHP_URL_PATH);

    if ($uploads_base_path && strpos($src_path, $uploads_base_path . '/') === 0) {
        $relative = ltrim(substr($src_path, strlen($uploads_base_path)), '/');

        if (!$relative) {
            return false;
        }

        $webp_url  = str_replace('/wp-content/uploads/', '/wp-content/uploads-webpc/uploads/', $src_raw) . '.webp';
        $webp_path = dirname($uploads_basedir) . '/uploads-webpc/uploads/' . $relative . '.webp';

        return [
            'url'  => $webp_url,
            'path' => $webp_path,
        ];
    }

    /**
     * 2. 处理当前主题目录图片
     * 规则:/wp-content/themes/your-theme/xxx.jpg
     * 对应:/wp-content/themes/your-theme/xxx.jpg.webp
     */
    $theme_baseurl = get_stylesheet_directory_uri();
    $theme_basedir = get_stylesheet_directory();

    $theme_base_path = parse_url(esc_url_raw($theme_baseurl), PHP_URL_PATH);

    if ($theme_base_path && strpos($src_path, $theme_base_path . '/') === 0) {
        $relative = ltrim(substr($src_path, strlen($theme_base_path)), '/');

        if (!$relative) {
            return false;
        }

        $webp_url  = $src_raw . '.webp';
        $webp_path = rtrim($theme_basedir, '/') . '/' . $relative . '.webp';

        return [
            'url'  => $webp_url,
            'path' => $webp_path,
        ];
    }

    return false;
}

function nbj_wrap_webp_picture($content) {
    if (is_admin() || is_feed() || (defined('REST_REQUEST') && REST_REQUEST)) {
        return $content;
    }

    if (stripos($content, '<img') === false) {
        return $content;
    }

    $uploads = wp_upload_dir();

    // 支持 jpg/png,以及 jpg/png 后面带 query string 的情况
    $pattern = '/<img\b[^>]*\bsrc=(["\'])([^"\']+\.(?:jpe?g|png)(?:\?[^"\']*)?)\1[^>]*>/i';

    return preg_replace_callback($pattern, function ($m) use ($uploads) {
        $img_tag = $m[0];
        $src     = html_entity_decode($m[2]);

        if (
            strpos($img_tag, 'data-nbj-webp') !== false ||
            strpos($src, 'uploads-webpc') !== false ||
            strpos($src, '.webp') !== false
        ) {
            return $img_tag;
        }

        $webp = nbj_get_webp_info($src, $uploads);

        if (!$webp || !is_file($webp['path'])) {
            return $img_tag;
        }

        $img_tag = preg_replace('/<img\b/i', '<img data-nbj-webp="1"', $img_tag, 1);

        return '<picture data-nbj-webp="1">'
            . '<source srcset="' . esc_url($webp['url']) . '" type="image/webp">'
            . $img_tag
            . '</picture>';
    }, $content);
}

add_filter('the_content', 'nbj_wrap_webp_picture', 999);
add_filter('widget_text_content', 'nbj_wrap_webp_picture', 999);

add_action('template_redirect', function () {
    if (
        !is_admin()
        && !is_feed()
        && !(defined('REST_REQUEST') && REST_REQUEST)
        && ob_get_level() === 0
    ) {
        ob_start('nbj_wrap_webp_picture');
    }
});

添加这个代码后,WordPress在前台输出内容时,就会先做一个判断,将你uploads目录下的图片文件全部添加<picture>标签。

<picture> 包裹的 <img> 标签webp输出

当支持Webp格式的浏览器(2026年基本上很难碰到不支持的设备了)默认会读取第一个source里面的webp格式图片,如果这个图片不存在或者还没转换完成,会降级读取下面的png原图(不支持webp格式的设备会直接读取原图,忽略webp)

webp格式被cloudflare缓存

所以,现在哪怕你是免费CloudFlare的用户,也可以让浏览器支持webp图片显示且图片走CDN流量了。


六、最终建议:WordPress 图片压缩提速的正确姿势

对于大多数使用 Cloudflare Free 的 WordPress 站长,推荐流程如下:

  1. 安装并启用 Converter for Media 插件。
  2. 在 WP Panel 的 Server 级 Nginx 自定义配置中添加官方规则。
  3. 主题后台函数文件增加HTML5的<picture> 标签代码。
  4. 清理一次网站和CDN的缓存,让资源刷新。

简单总结:

源站 Nginx 负责图片格式转换;Cloudflare 负责全球加速。

按上述方式配置后,你的 WordPress 站点就能在兼容旧浏览器的前提下,充分发挥 WebP/AVIF 的压缩优势,实现稳定、可持续的图片加载提速。

为什么我划掉了AVIF?因为这个格式转换比较费服务器资源,通常都是调用第三方的转换服务,是要付费项目,通常情况下Webp + CDN已经有不错的提速了。

用 WP Panel 托管你的 WordPress 网站

轻量、安全、永久免费。已有 0 台服务器 在使用 WP Panel 管理 WordPress 站点。一键建站、多层安全防护、FastCGI 全站缓存——只做 WordPress 运维真正需要的功能。

了解 WP Panel