管理しているサイトで、サーバーのファイルを見直していたときのことです。
その中の 1 つで、画像のフォルダのファイルが多いことに気づきました。
調べると、画像を 1 枚アップロードするたびに、どこでも使っていない縮小サイズの画像も作られていました。
今回検証したサイトでは、medium_large(768px)・1536x1536・2048x2048 の 3 つを使っていないことを確認しました。
この記事では、この 3 つを作らないようにするフィルターと、すでにあるファイルの片付け方、作業環境で確かめた結果をまとめます。
WordPress が作る縮小サイズ
WordPress は、画像をアップロードすると、元の画像のほかに、決まった大きさの画像を作ります。
管理画面の「設定」→「メディア」に出るのは、サムネイル・中サイズ・大サイズの 3 つだけです。
ほかに、画面に出ないサイズも作られています。
| 名前 | 大きさ(初めの値) | メモ |
|---|---|---|
thumbnail |
150×150(切り抜き) | 「設定」→「メディア」で変えられる |
medium |
300×300 まで | 「設定」→「メディア」で変えられる |
medium_large |
幅 768 まで | メディアの設定の画面には出ない |
large |
1024×1024 まで | 「設定」→「メディア」で変えられる |
1536x1536 |
1536×1536 まで | WordPress 5.3 から。画面には出ない |
2048x2048 |
2048×2048 まで | WordPress 5.3 から。画面には出ない |
| テーマ・プラグインのサイズ | それぞれ | add_image_size() で足したもの |
このサイトのテーマも、add_image_size() で独自のサイズを 4 つ足していました。
そのため、1 枚の画像から、たくさんのファイルができていました。
どのサイズが登録されているかを見る
まず、登録されているサイズを出して、テーマのどこで使っているかを見比べました。
<?php
// 登録されている縮小サイズを、名前と大きさで出す(検証用スクリプトの一部)
foreach ( wp_get_registered_image_subsizes() as $name => $size ) {
echo $name, ' ', $size['width'], 'x', $size['height'], ( $size['crop'] ? ' crop' : '' ), "\n";
}
| 書き方 | 役目 |
|---|---|
wp_get_registered_image_subsizes() |
登録されている縮小サイズを、名前・幅・高さ・切り抜くかで返す(WordPress 5.3 から) |
$size['crop'] |
決まった大きさに切り抜くサイズなら true |
次に、テーマのフォルダを、サイズの名前で grep しました。
本文の画像は large で、テーマの部品は thumbnail と独自のサイズで出していました。
medium_large・1536x1536・2048x2048 は、どこでも名前を指定して使っていませんでした。
1. 新しく作らない:intermediate_image_sizes_advanced
WordPress は、縮小サイズを作る前に、作るサイズの一覧を intermediate_image_sizes_advanced というフィルターに通します。
ここで一覧から外したサイズは、作られません。
<?php
// 使わない縮小サイズ(medium_large・1536x1536・2048x2048)を作らない
// 本文の画像は large、テーマは thumbnail と独自のサイズを使っている。この 3 つはどこでも使っていない。
function my_skip_image_sizes( $sizes ) {
unset( $sizes['medium_large'], $sizes['1536x1536'], $sizes['2048x2048'] );
return $sizes;
}
add_filter( 'intermediate_image_sizes_advanced', 'my_skip_image_sizes' );
| 書き方 | 役目 |
|---|---|
intermediate_image_sizes_advanced |
アップロードのときに作る縮小サイズの一覧を、作る前に変えられるフィルター |
$sizes |
サイズの名前をキーにした配列(幅・高さ・切り抜くか) |
unset( … ) |
作らないサイズを一覧から外す。テーマで使うサイズは外さない |
return $sizes; |
残ったサイズだけが作られる |
このフィルターが効くのは、これからアップロードする画像だけです。
すでにあるファイルは、そのまま残ります。
2. 今あるファイルを片付ける:WP-CLI のスクリプト
すでにある縮小サイズのファイルは、フィルターと同じ日に、スクリプトで片付けました。
ファイルを消すだけでは足りません。
画像のメタデータ(_wp_attachment_metadata)に、サイズの名前とファイル名が残っています。
残っていると、srcset などで、もうないファイルの URL が出てしまいます。
そのため、ファイルを消すのと一緒に、メタデータからもそのサイズを外します。
<?php
// 使わない縮小サイズ(medium_large・1536x1536・2048x2048)のファイルを消し、画像のメタデータからも外す。
// 元の画像と、ほかのサイズには触らない。WP-CLI から動かしたときだけ動く。
//
// 数えるだけ: wp eval-file wp-content/themes/my-theme/tools/remove-image-sizes.php
// 本当に消す: MY_DO=1 wp eval-file wp-content/themes/my-theme/tools/remove-image-sizes.php
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
exit;
}
$do = ( '1' === getenv( 'MY_DO' ) );
$targets = array( 'medium_large', '1536x1536', '2048x2048' );
$upload = wp_get_upload_dir();
$webpc = WP_CONTENT_DIR . '/uploads-webpc/uploads'; // Converter for Media の WebP の置き場所
$ids = get_posts(
array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'post_status' => 'inherit',
'posts_per_page' => -1,
'fields' => 'ids',
)
);
$count = array( 'images' => 0, 'files' => 0, 'webp' => 0, 'missing' => 0, 'shared' => 0 );
foreach ( $ids as $id ) {
$meta = wp_get_attachment_metadata( $id );
if ( empty( $meta['sizes'] ) || ! is_array( $meta['sizes'] ) ) {
continue;
}
$original = get_attached_file( $id );
if ( ! $original ) {
continue;
}
$dir = dirname( $original );
// 残すサイズが使っているファイル名(同じファイルをほかのサイズが使っていたら消さない)
$keep = array( basename( $original ) => true );
foreach ( $meta['sizes'] as $name => $size ) {
if ( ! in_array( $name, $targets, true ) && ! empty( $size['file'] ) ) {
$keep[ $size['file'] ] = true;
}
}
$hit = false;
foreach ( $targets as $name ) {
if ( empty( $meta['sizes'][ $name ]['file'] ) ) {
continue;
}
$hit = true;
$file = $meta['sizes'][ $name ]['file'];
unset( $meta['sizes'][ $name ] );
if ( isset( $keep[ $file ] ) ) {
$count['shared']++;
continue;
}
$path = $dir . '/' . $file;
if ( is_file( $path ) ) {
$count['files']++;
if ( $do ) {
unlink( $path );
}
} else {
$count['missing']++;
}
// WebP のコピー(uploads-webpc/uploads/年/月/ファイル名.webp)
$relative = ltrim( str_replace( wp_normalize_path( $upload['basedir'] ), '', wp_normalize_path( $path ) ), '/' );
$webp = $webpc . '/' . $relative . '.webp';
if ( is_file( $webp ) ) {
$count['webp']++;
if ( $do ) {
unlink( $webp );
}
}
}
if ( $hit ) {
$count['images']++;
if ( $do ) {
wp_update_attachment_metadata( $id, $meta );
}
}
}
WP_CLI::log(
sprintf(
'%s: images %d / files %d / webp %d / missing %d / shared %d',
$do ? 'deleted' : 'dry-run',
$count['images'],
$count['files'],
$count['webp'],
$count['missing'],
$count['shared']
)
);
| 書き方 | 役目 |
|---|---|
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) exit; |
WP-CLI から動かしたときだけ動く。ブラウザで URL を開かれても何もしない |
getenv( 'MY_DO' ) |
MY_DO=1 のときだけ消す。付けなければ数えるだけ |
get_posts( … 'post_type' => 'attachment' … ) |
メディアの画像を、ID だけ全部取る |
wp_get_attachment_metadata() |
画像のメタデータ。sizes にサイズごとのファイル名が入っている |
get_attached_file() |
画像のファイルの場所。縮小サイズのファイルは同じフォルダにある |
$keep |
残すサイズが使っているファイル名。同じファイルをほかのサイズも使っていたら消さない |
unlink() |
ファイルを消す |
uploads-webpc |
Converter for Media(WebP に変えるプラグイン)が作る WebP のコピー。使っていなければ見つからないだけ |
wp_update_attachment_metadata() |
サイズを外したメタデータを保存する |
WP_CLI::log() |
数えた結果を出す |
元の画像と、残すサイズのファイルには触りません。
動かす順
# サイトのフォルダ(wp-config.php がある所)で # 1. 数えるだけ(消さない) wp eval-file wp-content/themes/my-theme/tools/remove-image-sizes.php # 2. 本当に消す MY_DO=1 wp eval-file wp-content/themes/my-theme/tools/remove-image-sizes.php
| 順 | すること |
|---|---|
| 1 | アップロードのフォルダと DB のバックアップを取る |
| 2 | フィルターを入れたテーマを公開する(新しいファイルが増えないようにする) |
| 3 | 数えるだけで動かし、消すファイルの数と、「見つからなかった」「ほかのサイズと同じファイル」の数を見る |
| 4 | MY_DO=1 を付けて動かし、本当に消す |
| 5 | 記事のページを開き、画像が出ているかを見る |
エックスサーバーでは、SSH で入ると wp コマンド(WP-CLI)が使えます。
このサイトの本番は PHP 7.3 だったので、スクリプトもその書き方に合わせました。
確かめた結果
このサイトの作業環境(本番から複製したもの・WordPress 7.1.3・PHP 8.3)で確かめました。
検証用スクリプトで、作業環境の WordPress を読み込み、3000×2000 の JPEG の画像を作ってアップロードの処理(wp_generate_attachment_metadata())に通しました。
フィルターがあるとき・ないとき
| 試したこと | メタデータのサイズ | できたファイル |
|---|---|---|
| テーマのフィルターがあるとき | thumbnail・medium・large と、テーマの 4 つ | 8 個(元の画像・-scaled・縮小 6 個) |
| フィルターを外したとき(比べるため) | 上に加えて medium_large・1536×1536・2048×2048 | 11 個(768×512・1536×1024・2048×1365 が増えた) |
フィルターがあるときは、3 つのサイズのファイルが作られず、メタデータにも入りませんでした。
縮小が 7 サイズあるのにファイルが 6 個なのは、thumbnail とテーマのサイズの 1 つが同じ 150×150 で、1 つのファイルを一緒に使っていたためです。
どちらのときも、-scaled の付いた画像ができていました(下の「気をつけること」)。
片付けのスクリプト
作業環境の画像を全部消すわけにはいかないので、フィルターを外して入れた試しの画像 1 枚だけに、スクリプトを動かしました。
検証用スクリプトの中で WP_CLI の定数と WP_CLI::log() を用意し、pre_get_posts で、対象をその 1 枚にしぼりました。
| 試したこと | 結果 |
|---|---|
| 数えるだけ | 消す対象のファイル 3 個。ファイルは 11 個のまま(消していない) |
MY_DO=1 で消す |
3 個を消した。ファイルは 8 個になり、元の画像と -scaled は残った |
| 消したあとのメタデータ | medium_large・1536×1536・2048×2048 がなくなり、ほかのサイズは残った |
消したあとの srcset(large) |
1024w と 300w だけ。消したファイルの URL は出なかった |
| 作業環境の画像全体で、数えるだけ | 消す対象が見つかった。「見つからなかった」「ほかのサイズと同じファイル」は 0(何も消していない) |
本番の PHP 7.3 でも、php -l で書き方のエラーがないことを確かめました。
元に戻した
試しの画像は、確かめたあとに wp_delete_attachment() で消しました。
投稿の表とメタデータの表の行の数、アップロードのフォルダのファイルの数が、試す前と同じであることを確かめました。
気をつけること
- テーマやプラグインが
add_image_size()で足したサイズは、外さないでください。外すと、そのサイズで出している所が、元の画像や別のサイズで出るようになります。先にサイズの名前で grep して、使っていないものだけを外します -scaledの画像は、縮小サイズとは別の仕組みです。幅か高さが 2560px より大きい画像は、WordPress 5.3 から、2560px に縮めた-scaledの画像が作られ、それがふだん使う画像になります。2048x2048を外しても、-scaledは作られます(作業環境で確かめました)-scaledを作らないようにするには、big_image_size_thresholdのフィルターを使います(下のコード)。ただ、そうすると大きな元の画像がそのまま使われるので、このサイトでは止めていません(試していません)- 片付けのスクリプトは、
-scaledの画像と元の画像(メタデータのoriginal_image)には触りません。sizesの中の 3 つのサイズだけを見ています - 消したサイズは、
srcsetの候補から外れます。大きな画面で large より大きい画像を出したいテーマでは、外してよいか先に確かめてください - あとでサムネイルを作り直すプラグインを使うときも、フィルターが入っていれば、3 つのサイズは作られないはずです(試していません)
- 消す前に、アップロードのフォルダと DB のバックアップを取ってください
<?php // 大きな画像を 2560px に縮める動き(-scaled)を止める(このサイトでは使っていません・試していません) add_filter( 'big_image_size_threshold', '__return_false' );
まとめ
- WordPress は、設定の画面に出ない
medium_large・1536x1536・2048x2048も、アップロードのたびに作っている wp_get_registered_image_subsizes()でサイズを出し、テーマで使っていないものを確かめるintermediate_image_sizes_advancedで外したサイズは、新しいアップロードで作られない- すでにあるファイルは、消すのと一緒にメタデータからも外す。WP-CLI の
wp eval-fileで、数えるだけ → 消す、の順に動かす - テーマのサイズと
-scaledの画像は、別に考える
参考
- intermediate_image_sizes_advanced(developer.wordpress.org)
- wp_get_registered_image_subsizes()(developer.wordpress.org)
- add_image_size()(developer.wordpress.org)
- big_image_size_threshold(developer.wordpress.org)
- wp_update_attachment_metadata()(developer.wordpress.org)
- wp eval-file(developer.wordpress.org)


