我非常理解你想用纯代码来解决这个问题的心情。 本身就是一个追求极致轻量化的,少装一个插件,网站的运行负担就少一分。
用纯 PHP 代码“批量”转换媒体库中现有的图片,风险极高,通常不建议自己手写。
为什么纯代码批量转换存量图片是个“坑”?
- 服务器超时 (504 Gateway Timeout): 图像处理非常消耗 CPU 和内存。如果你有几百上千张图片,一个简单的 PHP 循环绝对会导致服务器资源耗尽并强制中断。
- 数据库关联断裂:WordPress 不仅仅是在硬盘上存了一张图。它在数据库里记录了原图路径、缩略图元数据(Meta Data),并且在你的文章内容(Post Content)里硬编码了 。如果你只改了文件,网站上的图片会全部裂开。
<img src="...jpg">
不过,既然你希望走代码流,这里有一个折中且最稳妥的纯代码方案:分为“拦截新图片”和“处理老图片”两步走。
第一步:纯代码实现“新上传图片”自动转 WebP
你可以将以下代码添加到 主题的functions.php 中。这段代码会在你未来上传 JPG/PNG 时,利用 WordPress 自带的 自动将其转换为 WebP,并替换掉原图。functions.php WP_Image_Editor
/**
* 上传图片时自动转换为 WebP 格式
*/
add_filter( 'wp_handle_upload', 'arkhe_auto_convert_to_webp' );
function arkhe_auto_convert_to_webp( $upload ) {
// 只处理 JPG 和 PNG
if ( $upload['type'] == 'image/jpeg' || $upload['type'] == 'image/png' ) {
$file_path = $upload['file'];
// 调用 WordPress 内置的图像编辑器 (依赖 GD 库或 Imagick)
$image_editor = wp_get_image_editor( $file_path );
if ( ! is_wp_error( $image_editor ) ) {
// 生成新的 WebP 文件路径
$webp_file = preg_replace( '/\.(jpg|jpeg|png)$/i', '.webp', $file_path );
// 保存为 WebP 格式
$saved = $image_editor->save( $webp_file, 'image/webp' );
if ( ! is_wp_error( $saved ) ) {
// 转换成功后,删除原 JPG/PNG 文件
@unlink( $file_path );
// 更新 WordPress 的上传信息
$upload['file'] = $webp_file;
$upload['url'] = preg_replace( '/\.(jpg|jpeg|png)$/i', '.webp', $upload['url'] );
$upload['type'] = 'image/webp';
}
}
}
return $upload;
}
优点: 零插件,不增加前端负担,未来上传的图片永远是 WebP格式,vps流量既节省,又加速网站打开速度,体验感一举两得。
第二步:处理“现存的老图片”(WP-CLI 方案)
对于媒体库里已经存在的老图片,不要用普通的 PHP 脚本。如果你懂一点服务器操作(SSH),行业标准做法是使用 WP-CLI(WordPress 命令行工具) 配合第三方包来处理,这样不会受限于 PHP 超时时间。
你可以使用 结合社区提供的 WebP 转换脚本,或者最安全的做法是:用代码生成 WebP 副本,但不修改数据库,通过 Nginx/Apache 规则让浏览器自动读取 WebP。wp-cli/media-command
Nginx 伪静态判断方案(服务器端无缝替换)
如果你将老图片通过本地工具(如 XnConvert)批量转换为 WebP,上传回 目录(保持文件名一致,仅后缀不同,例如 旁边多一个 )。wp-content/uploads/image.jpgimage.jpg.webp
然后在服务器的 Nginx 配置文件中添加以下规则:
# 检查浏览器是否支持 WebP,并且服务器上存在对应的 WebP 文件
location ~* ^/wp-content/uploads/(.+/)*(.+)\.(png|jpe?g)$ {
add_header Vary Accept;
if ($http_accept !~* "webp"){
break;
}
try_files $uri.webp $uri =404;
}
为什么这是神级操作?
绝对安全: 你完全不需要修改 WordPress 数据库里的文章内容。
兼容性满分: 支持 WebP 的浏览器(Chrome)会下载 WebP,老旧浏览器(IE)会继续下载原版 JPG,完美解决兼容问题。
直接在服务器底层跑命令行不仅效率极高,还能完美避开 PHP 超时的限制。配合 Nginx 的底层分发,这套方案堪称服务器运维级的最佳实践。
先用 Linux 命令批量生成 WebP 副本,再用 Nginx 规则实现无缝替换。
第一步:使用 Linux 命令行批量生成 WebP
我们需要用到一个极其轻量的官方工具 cwebp。它非常稳定,资源占用也完全可控。
1. 安装 WebP 转换工具 通过 SSH 登录你的服务器,根据你的操作系统运行以下命令安装环境:
- Ubuntu/Debian:
sudo apt-get install webp - CentOS/RHEL:
sudo yum install libwebp-tools
2. 执行批量转换脚本 进入你的 WordPress 网站图片上传目录。通常路径如下(请根据你的实际路径修改):
cd /你的网站根目录/wp-content/uploads/
进入目录后,直接复制并运行下面这段复合命令。它的逻辑是:递归查找所有 JPG/PNG 图片 -> 检查是否已有 WebP 副本 -> 如果没有,则以 80% 的质量生成一个同名的 .webp 副本。
find . -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -exec bash -c '
webp_path="$0.webp"
if [ ! -f "$webp_path" ]; then
echo "正在转换: $0"
cwebp -q 80 "$0" -o "$webp_path" -quiet
fi
' {} \;
提示:80% 是 WebP 的黄金质量点,能在肉眼看不出画质损失的前提下,把体积压缩 40% – 70%。这个脚本自带跳过机制,以后即便重复运行,也不会对已转换的图片进行二次处理。
第二步:配置 Nginx 实现“偷天换日”
现在硬盘上已经有了形如 image.jpg 和 image.jpg.webp 两个文件并存的情况。接下来我们要告诉 Nginx:如果访客的浏览器支持 WebP,就悄悄把 .webp 文件塞给他,但网址依然显示为 .jpg。
打开你网站的 Nginx 配置文件(如果你用的是宝塔面板,直接在“网站 – 设置 – 伪静态”或“配置文件”里修改)。在 server { ... } 块中,加入以下路由规则:
# 拦截 wp-content/uploads 下的图片请求
location ~* ^/wp-content/uploads/(.+/)*(.+)\.(png|jpe?g)$ {
# 告诉 CDN 或浏览器端缓存,这取决于请求头中的 Accept 字段
add_header Vary Accept;
# 默认后缀为空
set $ext "";
# 检查浏览器发送的请求头中是否包含 webp 支持
if ($http_accept ~* "webp") {
set $ext ".webp";
}
# 核心逻辑:
# 1. 尝试找带有 .webp 后缀的文件 ($uri$ext)
# 2. 如果没找到,就给原图 ($uri)
# 3. 如果连原图都没了,报 404
try_files $uri$ext $uri =404;
}
配置完成后,记得重载 Nginx 让规则生效:
nginx -t && nginx -s reload
如何验证是否成功?
- 用 Chrome 浏览器打开你的一篇 Arkhe 博客文章。
- 按下
F12打开开发者工具,切换到 Network (网络) 面板。 - 刷新页面,在列表中找到你的图片请求。
- 点开图片详情,查看 Response Headers (响应头)。如果看到
Content-Type: image/webp,说明 Nginx 已经成功实现了偷天换日,即使图片的 URL 后缀依然是.jpg。
在跑批量转换命令之前,建议先进入一个只有几张图片的子月份文件夹(比如 wp-content/uploads/2026/02/)里测试一下效果。