WordPress は、画像を 1 枚アップロードするたびに、大きさの違う画像(縮小版)を何枚も作ります。テーマが使う大きさも足されるので、使っていない大きさのファイルが、気づかないうちにたまっていきます。
自分で運営しているゲームの攻略サイト(画像 約 1,000 枚)で数えてみると、元の画像 610MB に対して、縮小版が約 2.1GB ありました。そのうち、どこにも使っていない大きさが約 600MB(WebP に変換したファイルを合わせると約 690MB)です。
この記事では、使っていない大きさの見つけ方、安全な消し方、これから作らせない方法を、実際に行った手順でまとめます。
WordPress が作る画像の大きさ
画像を 1 枚アップロードすると、次の大きさのファイルが作られます。
| 大きさの名前 | 大きさ | 決まる所・使い道 |
|---|---|---|
| thumbnail | 150px | 設定 → メディア で変えられる |
| medium | 300px | 設定 → メディア で変えられる |
| large | 1024px | 設定 → メディア で変えられる |
| medium_large | 幅 768px | 設定の画面には出ない。srcset(画面の幅に合わせて画像を選ぶ仕組み)の候補 |
| 1536×1536 | 1536px | WordPress 5.3 から。大きい画面向けの srcset の候補 |
| 2048×2048 | 2048px | WordPress 5.3 から。大きい画面向けの srcset の候補 |
| テーマが足す大きさ | テーマによる | add_image_size で登録されたもの(例:size1・size2・size3・size-card) |
1536×1536・2048×2048 は、元の画像がそれより大きいときだけ作られます。
全部を合わせると、1 枚の画像から 10 枚近いファイルができることもあります。
手順 1:大きさごとに、ファイルの数と容量を数える
WP-CLI(サーバーで WordPress を操作するコマンド)の wp eval-file で、次のファイルを動かします。読むだけで、何も消しません。エックスサーバーなど、SSH で WP-CLI が使えるサーバーを前提にしています。
<?php
// 画像の大きさごとに、ファイルの数と容量を数える(読むだけ・何も消さない)
// 使い方(WordPress のフォルダで): wp eval-file count-image-sizes.php
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
exit; // ブラウザから開かれても何もしない
}
$ids = get_posts(
array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'post_status' => 'inherit',
'posts_per_page' => -1,
'fields' => 'ids',
)
);
$stat = array( '(元の画像)' => array( 0, 0 ) );
foreach ( $ids as $id ) {
$original = get_attached_file( $id );
if ( ! $original || ! is_file( $original ) ) {
continue;
}
$stat['(元の画像)'][0]++;
$stat['(元の画像)'][1] += filesize( $original );
$meta = wp_get_attachment_metadata( $id );
if ( empty( $meta['sizes'] ) || ! is_array( $meta['sizes'] ) ) {
continue;
}
$dir = dirname( $original );
foreach ( $meta['sizes'] as $name => $size ) {
if ( ! isset( $stat[ $name ] ) ) {
$stat[ $name ] = array( 0, 0 );
}
$path = $dir . '/' . $size['file'];
if ( is_file( $path ) ) {
$stat[ $name ][0]++;
$stat[ $name ][1] += filesize( $path );
}
}
}
$registered = array_keys( wp_get_registered_image_subsizes() );
foreach ( $stat as $name => $s ) {
$note = ( '(元の画像)' === $name || in_array( $name, $registered, true ) ) ? '' : ' ← 今は登録されていない大きさ';
WP_CLI::log( sprintf( '%-16s %7d ファイル %9.1f MB%s', $name, $s[0], $s[1] / 1048576, $note ) );
}
攻略サイトでの結果です。
(元の画像) 1065 ファイル 609.9 MB medium 1065 ファイル 99.6 MB large 1065 ファイル 709.6 MB thumbnail 1065 ファイル 37.4 MB medium_large 1065 ファイル 476.4 MB size1 1065 ファイル 37.4 MB size2 1065 ファイル 222.4 MB size3 1065 ファイル 408.1 MB size-card 1065 ファイル 24.3 MB 1536x1536 112 ファイル 123.7 MB
large(710MB)や size3(408MB)は大きいですが、使っているなら残します。問題は、使っていない大きさがどれかです。
手順 2:どの大きさを使っているかを調べる
画像が使われる場所は、主に 3 つあります。それぞれ確かめます。
(1) 記事の本文に入れた画像
エディタで画像を入れると、img に class=”size-large” のような印が付きます。これを数えます。
<?php
// 公開中の記事・固定ページの本文に、どの大きさの画像が何か所入っているかを数える(読むだけ)
// 使い方(WordPress のフォルダで): wp eval-file find-size-usage.php
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
exit;
}
global $wpdb;
$contents = $wpdb->get_col( "SELECT post_content FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( 'post', 'page' )" );
foreach ( array_keys( wp_get_registered_image_subsizes() ) as $name ) {
$n = 0;
foreach ( $contents as $content ) {
// 画像を挿入すると img に class="size-大きさの名前" が付く(size-medium と size-medium_large を分けて数える)
$n += preg_match_all( '/\bsize-' . preg_quote( $name, '/' ) . '(?![\w-])/', $content );
}
WP_CLI::log( sprintf( '%-16s %6d か所', $name, $n ) );
}
thumbnail 0 か所 medium 0 か所 medium_large 0 か所 large 947 か所 1536x1536 0 か所 2048x2048 0 か所 size1 0 か所 size2 0 か所 size3 0 か所 size-card 0 か所
本文の画像は、すべて large でした。
(2) テーマのテンプレート
アイキャッチ画像などは、テーマのファイルの中で大きさを指定して出しています。テーマのフォルダを検索します。
grep -rnoE "(the_post_thumbnail|get_the_post_thumbnail|wp_get_attachment_image(_src|_url)?)\([^)]*\)" wp-content/themes/テーマのフォルダ
the_post_thumbnail('size1') … 10 か所
the_post_thumbnail('size2') … 4 か所
the_post_thumbnail('size3') … 1 か所
wp_get_attachment_image_src( $post_thumbnail_id, 'thumbnail')
wp_get_attachment_image_src( $post_thumbnail_id, 'size1')
テーマは size1・size2・size3・thumbnail を使っていました(size-card は、テーマのほかのファイルで使っていました)。
(3) 実際のページの HTML
ページビルダーやプラグインが別の場所に画像を持っていることもあるので、最後に、公開しているページの HTML に出てくる画像のファイル名を見ます。ファイル名の最後の「-768×432」のような部分で、大きさが分かります。
curl -s https://example.com/archives/123 | grep -oE "[-_0-9a-zA-Z]+-[0-9]+x[0-9]+\.(jpg|jpeg|png|webp)" | sort | uniq -c
トップ・記事・一覧など、作りの違うページをいくつか見ます。
調べた結果
- 使っている:large(本文)・size1〜3・size-card・thumbnail(テーマ)
- 管理画面で使うので残す:medium(メディアの一覧の表示に使う)
- どこでも使っていない:medium_large(476MB)・1536×1536(124MB)。srcset の候補に入っているだけ
medium_large などは srcset の候補として HTML に出るので、スマホなどの画面の幅によっては、ブラウザがこちらを選ぶことがあります。消すと、ブラウザはその次に合う大きさ(この例では large の 1024px)を選ぶので、スマホでの画像が少し重くなります。容量と表示の速さのどちらを取るかで決めてください。
手順 3:安全に消す
FTP やファイルマネージャーで「-768x」のファイルを消すだけだと、困ったことが起きます。
- WordPress は、画像の情報(メタデータ)に書かれた大きさから srcset を作るので、消したファイルが srcset に残り、画像が表示されないことがある(404 になる)。
- 同じファイル名を、残したい大きさも使っていることがある(元の画像が小さく、2 つの大きさが同じ寸法になったときなど)。
- WebP に変えるプラグイン(Converter for Media など)は、別のフォルダに WebP のファイルを持っている。こちらは残ったままになる。
そこで、ファイルを消すと同時に、画像の情報からも外す台本を作りました。既定は数えるだけで、FS_DO=1 を付けたときだけ消します。
<?php
// 使わない大きさの画像ファイルを消して、画像の情報(メタデータ)からも外す
// 元の画像と、残す大きさのファイルには触らない。Converter for Media の WebP のファイルも一緒に消す。
//
// 使い方(WordPress のフォルダで):
// 数えるだけ: wp eval-file remove-image-sizes.php
// 本当に消す: FS_DO=1 wp eval-file remove-image-sizes.php
if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
exit; // ブラウザから開かれても何もしない
}
$targets = array( 'medium_large', '1536x1536', '2048x2048' ); // 消す大きさ(サイトに合わせて変える)
$do = ( '1' === getenv( 'FS_DO' ) );
$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,
'bytes' => 0,
'webp_files' => 0,
'webp_bytes' => 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 );
if ( ! empty( $meta['original_image'] ) ) {
$keep[ $meta['original_image'] ] = 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 ] ); // 画像の情報から外す(srcset に出なくなる)
if ( isset( $keep[ $file ] ) ) {
$count['shared']++; // 同じファイルを残す大きさが使っているので消さない
continue;
}
$path = $dir . '/' . $file;
if ( is_file( $path ) ) {
$count['files']++;
$count['bytes'] += filesize( $path );
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_files']++;
$count['webp_bytes'] += filesize( $webp );
if ( $do ) {
unlink( $webp );
}
}
}
if ( $hit ) {
$count['images']++;
if ( $do ) {
wp_update_attachment_metadata( $id, $meta );
}
}
}
WP_CLI::log(
( $do ? '消した' : '数えただけ(消していない)' ) . sprintf(
':画像 %d 枚・ファイル %d(%.1f MB)・WebP のファイル %d(%.1f MB)・見つからなかった %d・残す大きさと同じファイルで残した %d',
$count['images'],
$count['files'],
$count['bytes'] / 1048576,
$count['webp_files'],
$count['webp_bytes'] / 1048576,
$count['missing'],
$count['shared']
)
);
動かし方
cd ~/example.com/public_html # WordPress のフォルダ(サーバーに合わせて変える) wp eval-file remove-image-sizes.php # 数えるだけ FS_DO=1 wp eval-file remove-image-sizes.php # 数を確かめてから、本当に消す
数えるだけの結果です。手順 1 の medium_large(1,065 ファイル)と 1536×1536(112 ファイル)の合計と合っていることを確かめてから、消しました(1 枚の違いは、その日にアップロードした画像です)。
数えただけ(消していない):画像 1066 枚・ファイル 1178(600.2 MB)・WebP のファイル 1176(86.3 MB)・見つからなかった 0・残す大きさと同じファイルで残した 0
- サーバーの WP-CLI が新しい PHP に合っていないと、「PHP Deprecated: …」がたくさん出ることがあります。台本の動きとは関係ありません。見づらいときは
wp eval-file remove-image-sizes.php 2>&1 | grep -v Deprecatedで隠せます。 - 台本はブラウザから開かれても何もしませんが、終わったらサーバーから消しておくと安心です。
消す前の控え
縮小版は元の画像から作り直せるもの(Regenerate Thumbnails などのプラグインで作り直せる)なので、ファイルを全部控える必要はあまりありません。それでも、レンタルサーバーの自動バックアップがあるか、消す前に確かめておきます。
消したあとに確かめること
- トップ・記事・一覧などのページで、画像がすべて出るか。攻略サイトでは 8 ページに出てくる画像の URL 565 個を全部開いて、565 個とも表示されることを確かめました。
- ページの HTML に、消した大きさ(-768x・-1536x)のファイル名が残っていないか(手順 2 の curl で確かめられます)。
- PHP のエラーが出ていないか。
手順 4:これから作らせない
消しても、新しく画像を上げると、また同じ大きさが作られます。intermediate_image_sizes_advanced フィルターで、作る大きさの一覧から外します。
/*----------------------------------------------------
使わない大きさの画像を、これから作らない
----------------------------------------------------*/
if ( ! function_exists( 'fs_skip_image_sizes' ) ) {
function fs_skip_image_sizes( $sizes ) {
// medium_large(768px)・1536x1536・2048x2048 を作らない(サイトに合わせて変える)
unset( $sizes['medium_large'], $sizes['1536x1536'], $sizes['2048x2048'] );
return $sizes;
}
add_filter( 'intermediate_image_sizes_advanced', 'fs_skip_image_sizes' );
}
- medium_large は設定の画面にないので、このフィルターで外すのが確実です。
- テーマが使っている大きさ(手順 2 で見つけたもの)は外さないでください。外すと、その大きさの代わりに元の画像などが使われ、表示が崩れたり重くなったりします。
- テーマを更新すると functions.php が上書きされるテーマでは、子テーマか、Code Snippets などに入れます。
WordPress 5.3 からは、幅や高さが 2560px を超える画像を自動で縮小し「-scaled」の付いたファイルを作ります(big_image_size_threshold)。これを止めると、数 MB の元の画像がそのまま使われることがあるので、止めないほうが安全です。
結果
- 消したファイル:縮小版 1,178 + WebP のファイル 1,176 = 約 2,350 ファイル
- 空いた容量:約 690MB(縮小版 600MB + WebP 86MB)
- 表示:画像はすべて出る。HTML に消した大きさのファイル名は 0
- これから上げる画像は、medium_large・1536×1536・2048×2048 を作らない
同じことを画像 約 2,000 枚の別のサイトでも数えましたが、使っていない大きさは約 43MB と小さかったので、そちらは見送りました。サイトによって差が大きいので、まず手順 1 で数えてから決めるのがおすすめです。
まとめ
- まず大きさごとに数える(手順 1)。消すかどうかは、容量を見てから決める。
- 使っているかは、本文・テーマ・実際のページの HTML の 3 つで確かめる。medium は管理画面で使うので残す。
- ファイルだけ消さない。画像の情報(メタデータ)からも外し、WebP のファイルも一緒に消す。まず数えるだけで動かす。
- intermediate_image_sizes_advanced で、これから作らせない。


