搜索全站
主题 14 分钟阅读

add_image_size 自定义缩略图:新增尺寸后必须重建

加了 add_image_size 前台却显示原图?讲清尺寸注册时机、裁剪参数、后台可选的钩子、重建缩略图的两种方式,以及删除尺寸后残留文件的清理。

U
UFO_PF 2020-07-17 · 阅读 14 分钟
ad 主题
阅读提示
本文约 5,216 字,预计阅读 14 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:加了尺寸,前台还是加载 2000px 原图

列表页要显示 400×260 的卡片图,于是在 functions.php 里加了 add_image_size( 'card', 400, 260, true ),模板里改写成 the_post_thumbnail( 'card' )。刷新一看,图片确实是 400 宽——但打开网络面板,下载的是 2000×1300 的原图,页面上三十张卡片总共 8MB,移动端直接卡死。

原因很简单:这些图片是三个月前上传的,add_image_size 只对之后上传的图生成新尺寸。老图没有对应的文件,the_post_thumbnail() 找不到就退回原图。

原理分析:裁剪发生在上传那一刻

WordPress 的媒体处理流程是:

上传原图 → wp_generate_attachment_metadata()
        → wp_getimagesize() 读取尺寸
        → 遍历所有已注册尺寸(含核心的 thumbnail/medium/medium_large/large)
        → 逐个用 WP_Image_Editor(GD 或 Imagick)裁剪
        → 生成 文件名-宽x高.jpg,写入 _wp_attachment_metadata

关键点有三个:

  1. 尺寸列表是”上传时的快照”。 结果写进 wp_postmeta 的 _wp_attachment_metadata 里,形如:
array(
    'width'  => 2000,
    'height' => 1300,
    'file'   => '2026/01/photo.jpg',
    'sizes'  => array(
        'thumbnail'    => array( 'file' => 'photo-150x150.jpg', 'width' => 150, 'height' => 150 ),
        'medium'       => array( 'file' => 'photo-300x195.jpg', 'width' => 300, 'height' => 195 ),
        'card'         => array( 'file' => 'photo-400x260.jpg', 'width' => 400, 'height' => 260 ),
    ),
)
  1. 核心内置四个尺寸,可在「设置 → 媒体」里改:thumbnail(150×150)、medium(最大 300)、medium_large(768 宽,无后台设置项)、large(最大 1024)。
  2. 取图时按名字查 sizes 数组,查不到就退回 large 或原图,不会自动生成。

add_image_size() 的第四个参数决定裁剪方式:

值 行为
false(默认) 等比缩放,最长边不超过设定值
true 硬裁剪到精确尺寸,居中裁
array( 'left', 'top' ) 硬裁剪,指定裁切锚点(left/center/right × top/center/bottom)

保姆级实操

第 1 步:注册尺寸

add_action( 'after_setup_theme', function () {
    add_theme_support( 'post-thumbnails' );

    set_post_thumbnail_size( 1200, 675, true );   // 特色图片默认尺寸

    add_image_size( 'card', 400, 260, true );                    // 卡片:硬裁剪居中
    add_image_size( 'card-wide', 800, 300, true );               // 宽卡:硬裁剪居中
    add_image_size( 'hero', 1920, 720, array( 'center', 'top' ) ); // 头图:锚点靠上
    add_image_size( 'avatar-lg', 240, 240, true );
    add_image_size( 'logo-soft', 300, 0 );                       // 只限宽,高度自适应
} );

高度为 0 时表示不限高,等比缩放。注册必须挂在 after_setup_theme,因为 add_theme_support( 'post-thumbnails' ) 也在这里。

第 2 步:前台调用

// 列表卡片
if ( has_post_thumbnail() ) {
    the_post_thumbnail( 'card', array(
        'class'   => 'card__img',
        'loading' => 'lazy',
        'alt'     => the_title_attribute( array( 'echo' => false ) ),
    ) );
}

// 需要拿 URL 自己拼接 srcset 时
$src = wp_get_attachment_image_src( get_post_thumbnail_id(), 'hero' );
printf( '<img src="%s" width="%d" height="%d" alt="">', esc_url( $src[0] ), (int) $src[1], (int) $src[2] );

推荐直接用 wp_get_attachment_image(),它会自动输出 srcset 与 sizes:

echo wp_get_attachment_image(
    get_post_thumbnail_id(),
    'card',
    false,
    array( 'class' => 'card__img', 'loading' => 'lazy' )
);

上面这段代码通常写在文章卡片片段里,卡片的拆分与复用方式见get_template_part 拆分复用模板片段。

第 3 步:让后台编辑器能选到新尺寸

默认新尺寸不会出现在「插入媒体」的尺寸下拉框里,需要挂 image_size_names_choose:

add_filter( 'image_size_names_choose', function ( $sizes ) {
    return array_merge( $sizes, array(
        'card'      => '卡片 400×260',
        'card-wide' => '宽卡 800×300',
        'hero'      => '头图 1920×720',
    ) );
} );

后台「外观 → 自定义」里若也需要选择图片类设置项,控件写法见主题选项面板实现方式对比。

第 4 步:重建缩略图(关键一步)

新尺寸只对之后上传的图生效,老图必须重建。两种做法:

命令行(推荐,速度快、可断点):

# 重建全部
wp media regenerate --yes

# 只重建缺了 card 尺寸的图(WP-CLI 2.x 支持 --image_size)
wp media regenerate --image_size=card --yes

# 只重建指定附件
wp media regenerate 123 456 --yes

后台图形界面:装 Regenerate Thumbnails(作者 Alex Mills)插件,在「工具 → Regenerate Thumbnails」里点开始。媒体库超过一万张时,插件会分批执行,需要保持页面打开,容易超时,这种情况一律用 WP-CLI。

重建只会新增缺失的尺寸,不会删除已有文件,所以反复执行是安全的。

第 5 步:核对生成结果

wp eval '$m = wp_get_attachment_metadata( 123 ); print_r( array_keys( $m["sizes"] ) );'
wp post meta get 123 _wp_attachment_metadata

文件系统侧同步确认:

ls -lh wp-content/uploads/2026/01/ | grep photo-

第 6 步:清理废弃尺寸

删掉某个尺寸的注册代码后,已生成的文件不会自动消失,会长期占着磁盘。清理办法是先解除注册再删文件与元数据:

add_filter( 'intermediate_image_sizes_advanced', function ( $sizes ) {
    unset( $sizes['card-wide'] );   // 阻止后续上传再生成
    return $sizes;
} );
# 找出所有 card-wide 文件并确认后删除(先 ls 确认,再 rm)
find wp-content/uploads -name "*-800x300.*" -print
find wp-content/uploads -name "*-800x300.*" -delete
wp media regenerate --yes   # 顺便刷新元数据

常见踩坑

  1. 注册尺寸后没重建。 老图继续加载原图,页面体积暴涨,这是最高频的失误。
  2. 硬裁剪 true 用在含透明通道的 PNG 上。 裁剪区域外的透明像素会被填充成白底或黑底,视 WP_Image_Editor 实现而定。Logo 类图片应改用不裁剪的等比尺寸。图片地址输出时必须走 esc_url(),详见输出转义规范 esc_html esc_attr esc_url。
  3. 尺寸改了但文件名没变。 把 card 从 400×260 改成 420×280 后,老文件仍是 photo-400x260.jpg,元数据与新尺寸对不上,必须重新 wp media regenerate。
  4. 原图比设定尺寸小。 上传一张 300px 宽的图,系统不会放大生成 400 宽的 card,元数据里就没有这一项,前台会退回原图。模板里要有兜底逻辑。
  5. add_image_size 写在 init 上。 太晚,上传流程读不到。统一挂 after_setup_theme。
  6. 案例: 某站给移动端专门加了 mobile-thumb 尺寸,跑完 wp media regenerate 后磁盘占用从 3.2GB 涨到 4.8GB。原因是历史上有六种旧尺寸(三个废弃主题留下的)从未清理,重建时它们也被一并重新生成。后来先用 intermediate_image_sizes_advanced 过滤掉废弃尺寸、删除对应文件,再重建,最终降到 2.6GB。教训是:重建之前先梳理一遍当前注册的尺寸清单:
wp eval 'print_r( get_intermediate_image_sizes() );'
  1. 对象存储(OSS/COS)上的图片重建超时。 远程裁剪需要先把原图下载到本地再上传,网络慢时批量重建极易中断。建议分批:wp media regenerate --yes 配合按月份目录拆分执行。

总结

add_image_size 的完整流程是”注册 → 调用 → 后台可选 → 重建 → 核对”,中间任何一步省略都会导致前台加载错误尺寸。判断标准:新增尺寸后必须跑一次 wp media regenerate,删除尺寸后必须清理残留文件;图片量大的站优先用 WP-CLI 而非后台插件;每次调整尺寸数值都要重建,因为文件名里带着宽高。最后用 wp_get_attachment_image() 输出,让核心自动处理 srcset,移动端就不必下载桌面端大图。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。