如何关闭 WordPress 的 -scaled 图片(big_image_size_threshold)
用 big_image_size_threshold 过滤器抬高或去掉 2560px 上限,解决 WordPress 图片发虚的问题,顺便看看为什么大家都漏掉了重新上传这一步。
发布于
给 big_image_size_threshold 加一个返回 false 的过滤器,WordPress 就不会在上传时生成 -scaled 副本了。改成返回一个数字,则是把上限抬高而不是取消。两种写法都放在 functions.php 或一个小的 mu-plugin 里,而且都只对过滤器生效之后上传的图片起作用。
// Disable the cap entirely — no -scaled copies at all.
add_filter( 'big_image_size_threshold', '__return_false' );
// Or just raise it. Longest edge, in pixels.
add_filter( 'big_image_size_threshold', function () {
return 3840;
} );
WordPress 到底做了什么
从 WordPress 5.3 开始,每一次上传都会被测量最长边。如果这条边大于 big_image_size_threshold(默认是 2560px),WordPress 会把图片重新编码缩到这个上限,存成 your-photo-scaled.jpg,并改写附件元数据,让 full 尺寸指向这个缩小后的副本。
你的原图没有被删。它还在磁盘上,文件名不变,也记录在附件元数据里,在 PHP 里可以通过 wp_get_original_image_path() 拿到。但前台没有任何地方会输出它。区块编辑器不会,srcset 不会,媒体库预览也不会。它就躺在那里,充当一份存档。
之后所有派生文件都是从这个缩小后的文件生成的,不是从你上传的那个:
| 尺寸 | 由哪个文件生成 |
|---|---|
full | -scaled 副本 |
large、medium_large、medium、thumbnail | -scaled 副本 |
通过 add_image_size 注册的自定义尺寸 | -scaled 副本 |
主题和插件的尺寸,例如 woocommerce_thumbnail | -scaled 副本 |
srcset 候选文件 | -scaled 副本 |
正是这一点,让特别多人栽了跟头。
为什么”我明明上传的是清晰图,看着却发虚”多半是这个原因
有两件事同时在发生,而只有其中一件是明显的。
明显的那件是分辨率。你上传一张 4000px 的照片做通栏头图,WordPress 只给浏览器 2560px。在普通屏幕上填满 1600px 的容器,没人看得出来。但在 2 倍视网膜屏上,这个容器需要大约 3200 个真实像素,却只拿到 2560,浏览器只能把差额放大补上。于是边缘发软、细节糊成一团、图里的文字变毛。
不那么明显的那件是重新编码。-scaled 副本并不是你原文件的无损裁切。WordPress 会解码你上传的图、缩放、再按它自己的 JPEG 质量设置重新压缩一遍。如果你的原图本来就是从 Lightroom 或手机里出来的压缩 JPEG,那这就是第二代编码:压缩失真叠在压缩失真上面。细部纹理、胶片颗粒和平滑渐变受影响最严重。哪怕像素尺寸看着够用,你也能看出来。
改动之前先确认一下。在新标签页里打开这张图,读一下网址里的文件名。带 -scaled.jpg 就说明上限触发了。而像 -1536x1024.jpg 这样的尺寸后缀是另一回事——那是 srcset 挑了一个太小的中间尺寸,这个阈值过滤器帮不了你。
在服务器上:
find wp-content/uploads -name '*-scaled.*' | wc -l
如果这个数字很大,说明这个上限一直在塑造你的整个图库。
你也可以把一个文件丢进关闭 scaled 图片工具,在决定采用某个设置之前,先看看这个源文件会不会触发阈值、缩小后的副本会落在什么尺寸上。
实话实说的取舍
大多数文章告诉你关掉上限会更占磁盘。这话说反了,值得说准确一点。
单张图片占的磁盘反而略微减少。 阈值开着时,WordPress 会同时存你的原图和一个大的缩小副本。关掉之后,你只保留原图。一个文件,而不是两个。
带宽和页面体积会上升,有时候上升得很厉害。 上限关掉后,full 就是你未经处理的上传文件。任何链接或渲染 full 尺寸的地方——灯箱、图库插件、“查看原图”链接、请求 full 做头图的主题——现在输出的可能是 6MB 而不是 900KB。在移动端这是实打实的 Largest Contentful Paint 问题,而且图片 CDN 也不一定救得了你,因为有些 CDN 超过某个体积就直接放行不处理了。
上传时的内存占用会上升。 在 PHP 里处理一张 6000px 的图,比处理 2560px 的要吃掉多得多的内存。在 PHP 内存限制很低的廉价共享主机上,关掉上限很可能让你开始遇到上传失败或缩略图只生成了一半。把阈值提到 3840 而不是直接去掉,是这同一个改动里更稳妥的版本。
所以对大多数站点来说,合理的默认做法是把数字调大,而不是取消。只有当你输出的图片确实需要完整分辨率时,取消才是对的:印刷级图库、商品放大、建筑摄影,任何需要用户去细看原图的场景。
正确地落实这个改动
1. 把过滤器放在能活下来的地方。 子主题的 functions.php 可以用。单文件的 mu-plugin 更好,因为换主题不会悄悄把它撤销掉。
<?php
/**
* Plugin Name: Raise big image threshold
*/
add_filter( 'big_image_size_threshold', function () {
return 3840;
} );
2. 把受影响的图片重新上传一遍。 这就是大家会漏掉、然后断定”过滤器没生效”的那一步。阈值只在上传那一刻判断一次。已有的附件会永远保留它们的旧元数据。删掉附件、重新上传,然后把文章里的引用改过来。
3. 别指望重新生成缩略图能救回什么。 WP-CLI 的 wp media regenerate 是根据元数据里所谓的 full 文件来重建中间尺寸的——而对一张已经被压过的图来说,那就是 -scaled 副本。它没法还原已经丢掉的细节。重新上传之后拿它来收尾很有用,单独拿它当解决办法则毫无用处。
4. 检查结果,不要假设。 重新上传之后,在前台打开这张图,再读一遍文件名。没有 -scaled,说明过滤器已经生效了。
什么时候关掉它是错的
如果你的源图本来就不到 2560px、看着却还是发虚,那阈值从头到尾就没参与过。问题是显示区域比可用的像素还大,答案是换更大的源文件或者更小的容器——不是这个过滤器。
如果输出的文件名带的是尺寸后缀而不是 -scaled,那是 srcset 选了一个小候选。这通常是主题声明的内容宽度和图片实际渲染的区域对不上。关掉上限对此毫无影响。
还有,如果某个插件把你的 src 改写到了优化服务或 CDN 代理上,那么在你搞清楚那个代理输出的是什么之前,上面这些都不适用。把 WordPress 应该生成的东西和浏览器实际加载的东西对比一下;两者对不上时,去看夹在它们中间的那个环节。
FAQ
常见问题
怎么在 WordPress 里关闭 scaled 图片?
给 big_image_size_threshold 加一个返回 false 的过滤器,放进 functions.php 或者一个小的 mu-plugin 里。返回 false 会把上限彻底关掉,上传的图片保持原始尺寸,也不会再生成 -scaled 副本。如果返回的是一个数字,比如 3840,那就是把上限抬高,而不是取消。
WordPress 文件名里的 -scaled 后缀是什么意思?
它表示这是 WordPress 重新编码过的副本,因为你上传的图片最长边超过了 2560px。这个副本会在整个站点上充当 full 尺寸。你的原图还在磁盘上、还是原来的文件名,但前台没有任何地方链接到它,所有缩略图和 srcset 候选文件都是从这个缩小后的副本生成的。
关掉 scaled 图片会更占磁盘空间吗?
单张图片通常反而占得稍微少一点,因为 WordPress 不再在你的原图旁边多写一个大文件。真正的代价是带宽,不是存储。上限关掉之后,任何链接到 full 尺寸的地方都会输出你未经处理的原图,在手机网络下可能是好几兆。
关掉这个阈值,能修好已经发虚的图片吗?
不能。过滤器只对新上传的图片生效。媒体库里已有的图片,元数据仍然指向它们的缩小副本,而重新生成缩略图也只是从同一个被压过的文件重建各个尺寸。想把分辨率找回来,只能在过滤器生效之后删掉附件、重新上传一次。
2560px 这个阈值该保留吗?
对绝大多数内容型网站来说,该保留。2560px 的源文件足以在 2 倍像素密度下填满 1280px 的显示区域,这是最常见的情况。如果你做的是通栏大图、商品放大或摄影图库,把它提到 3840。只有在你确实需要输出未经处理的原图时,才把它整个关掉。