2026年10月20日
2026年10月20日
WordPressの画像最適化エラーを解決する方法
はじめに
WordPressにアップロードした画像のファイルサイズが数MBあってページ読み込みが遅い・WebP形式への変換が機能しない・投稿に画像を挿入するとサムネイルが表示されない・大きな画像をアップロードしようとするとPHPのメモリエラーで失敗するといった問題は、GDライブラリやImageMagickの設定不備・PHPメモリ制限・画像処理フックの設定漏れが原因です。
症状・原因
- アップロードした画像が元のサイズのまま表示されてページ速度に影響している
add_image_size()で登録したカスタムサイズのサムネイルが生成されない- WebP変換プラグインを使っているが
.webpファイルが作成されない - 1MB以上の画像をアップロードすると「HTTPエラー」または「メモリ不足」が発生する
解決手順
ステップ1:画像処理環境を診断する
# WP-CLIで画像処理ライブラリを確認
wp eval "
\$editor = wp_get_image_editor(ABSPATH . 'wp-includes/images/blank.gif');
if (is_wp_error(\$editor)) {
echo 'Image editor error: ' . \$editor->get_error_message() . PHP_EOL;
} else {
echo 'Image editor: ' . get_class(\$editor) . PHP_EOL;
}
// GDライブラリ確認
if (function_exists('gd_info')) {
\$gd = gd_info();
echo 'GD version: ' . \$gd['GD Version'] . PHP_EOL;
echo 'WebP support: ' . (isset(\$gd['WebP Support']) && \$gd['WebP Support'] ? 'yes' : 'no') . PHP_EOL;
}
// ImageMagick確認
if (class_exists('Imagick')) {
\$im = new Imagick();
echo 'ImageMagick version: ' . \$im->getVersion()['versionString'] . PHP_EOL;
echo 'WebP support: ' . (in_array('WEBP', \$im->queryFormats()) ? 'yes' : 'no') . PHP_EOL;
}
"
# アップロード済み画像のサムネイル状況確認
wp eval "
\$attachments = get_posts(['post_type' => 'attachment', 'posts_per_page' => 5, 'post_mime_type' => 'image']);
foreach (\$attachments as \$att) {
\$meta = wp_get_attachment_metadata(\$att->ID);
\$sizes = isset(\$meta['sizes']) ? count(\$meta['sizes']) : 0;
echo \$att->post_title . ': ' . \$sizes . ' サイズ' . PHP_EOL;
}
"
# PHPメモリ設定確認
wp eval "
echo 'memory_limit: ' . ini_get('memory_limit') . PHP_EOL;
echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . PHP_EOL;
echo 'post_max_size: ' . ini_get('post_max_size') . PHP_EOL;
echo 'max_execution_time: ' . ini_get('max_execution_time') . PHP_EOL;
"
ステップ2:PHPメモリとアップロード制限を修正する
// wp-config.php: メモリ制限を増やす
define('WP_MEMORY_LIMIT', '256M');
define('WP_MAX_MEMORY_LIMIT', '512M');
# .htaccess: PHPの制限を緩和
php_value memory_limit 256M
php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value max_execution_time 300
// functions.php: 画像の最大サイズを設定
add_filter('big_image_size_threshold', function(int $threshold): int {
// デフォルト2560px → 1920pxに変更
return 1920;
});
// アップロード時の画質設定
add_filter('jpeg_quality', function(): int {
return 82; // デフォルト82、ファイルサイズと品質のバランス
});
add_filter('wp_editor_set_quality', function(): int {
return 82;
});
ステップ3:サムネイルを再生成する
# 全画像のサムネイルを再生成
wp media regenerate --yes
# 特定の画像だけ再生成
wp media regenerate 123 456 789
# 特定のサイズだけ再生成(--image_sizeは非公式オプション)
wp eval "
\$attachments = get_posts(['post_type' => 'attachment', 'posts_per_page' => -1, 'post_mime_type' => 'image']);
foreach (\$attachments as \$att) {
\$file = get_attached_file(\$att->ID);
if (\$file && file_exists(\$file)) {
\$meta = wp_generate_attachment_metadata(\$att->ID, \$file);
wp_update_attachment_metadata(\$att->ID, \$meta);
echo 'Regenerated: ' . \$att->post_title . PHP_EOL;
}
}
"
// functions.php: カスタムサムネイルサイズを登録
add_action('after_setup_theme', function(): void {
add_theme_support('post-thumbnails');
// カスタムサイズ追加
add_image_size('hero', 1920, 600, true); // ヒーロー画像(クロップ)
add_image_size('card', 400, 300, true); // カード画像
add_image_size('og-image', 1200, 630, true); // OGP画像
// 不要なデフォルトサイズを削除してサーバー負荷軽減
add_filter('intermediate_image_sizes_advanced', function(array $sizes): array {
unset($sizes['medium_large']); // 768px幅(通常不要)
return $sizes;
});
});
ステップ4:WebP自動変換を実装する
// functions.php: WebP変換とフォールバック配信
// ① アップロード時にWebPを自動生成
add_filter('wp_generate_attachment_metadata', function(array $meta, int $attachment_id): array {
$file = get_attached_file($attachment_id);
if (!$file || !in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), ['jpg', 'jpeg', 'png'], true)) {
return $meta;
}
$webp_file = preg_replace('/\.(jpe?g|png)$/i', '.webp', $file);
// GDを使ってWebP生成
if (function_exists('imagewebp')) {
$image = match(true) {
str_ends_with(strtolower($file), '.png') => imagecreatefrompng($file),
default => imagecreatefromjpeg($file),
};
if ($image) {
imagewebp($image, $webp_file, 82);
imagedestroy($image);
}
}
return $meta;
}, 10, 2);
// ② srcsetにWebPを追加
add_filter('wp_calculate_image_srcset', function(array $sources): array {
foreach ($sources as &$source) {
$webp = preg_replace('/\.(jpe?g|png)$/i', '.webp', $source['url']);
$webp_path = str_replace(
content_url(),
WP_CONTENT_DIR,
$webp
);
if (file_exists($webp_path)) {
$source['url'] = $webp;
}
}
unset($source);
return $sources;
});
// ③ picture要素でWebPとフォールバックを出力
add_filter('the_content', function(string $content): string {
return preg_replace_callback(
'/<img([^>]+src=["\']([^"\']+\.(?:jpe?g|png))["\'][^>]*)>/i',
function(array $m): string {
$webp = preg_replace('/\.(jpe?g|png)$/i', '.webp', $m[2]);
$webp_path = str_replace(content_url(), WP_CONTENT_DIR, $webp);
if (!file_exists($webp_path)) {
return $m[0];
}
return sprintf(
'<picture><source srcset="%s" type="image/webp"><img%s></picture>',
esc_url($webp),
$m[1]
);
},
$content
);
});
ステップ5:画像の遅延読み込みとCLSを防止する
// functions.php: 画像パフォーマンス最適化
// ① width/heightを自動付与してCLSを防ぐ
add_filter('wp_get_attachment_image_attributes', function(array $attr, WP_Post $attachment, $size): array {
// loading=lazyを確保
if (!isset($attr['loading'])) {
$attr['loading'] = 'lazy';
}
// decoding=asyncを追加
$attr['decoding'] = 'async';
// width/heightが未設定の場合は補完
if (!isset($attr['width']) || !isset($attr['height'])) {
$image_data = wp_get_attachment_image_src($attachment->ID, $size);
if ($image_data && count($image_data) >= 3) {
$attr['width'] = $image_data[1];
$attr['height'] = $image_data[2];
}
}
return $attr;
}, 10, 3);
// ② アイキャッチ画像はfetchpriority=highで先読み
add_action('wp_head', function(): void {
if (!is_singular() || !has_post_thumbnail()) {
return;
}
$thumbnail_id = get_post_thumbnail_id();
$thumbnail_url = wp_get_attachment_image_url($thumbnail_id, 'large');
if ($thumbnail_url) {
printf(
'<link rel="preload" as="image" href="%s" fetchpriority="high">%s',
esc_url($thumbnail_url),
PHP_EOL
);
}
}, 1);
# 未使用の添付ファイルを削除してディスクを節約
wp eval "
\$orphans = get_posts([
'post_type' => 'attachment',
'post_parent' => 0,
'posts_per_page' => -1,
'post_status' => 'inherit',
]);
echo '未添付ファイル数: ' . count(\$orphans) . PHP_EOL;
"
# 画像ファイルのサイズ確認
wp eval "
\$upload_dir = wp_upload_dir();
echo 'アップロードディレクトリ: ' . \$upload_dir['basedir'] . PHP_EOL;
"
注意事項
wp media regenerateはサーバーに大きな負荷をかけます。記事数が多いサイトでは深夜に実行するか、--limitオプションで分割して実行してください- WebP変換を有効にする場合、GDライブラリのWebPサポートが有効になっている必要があります。
phpinfo()でGD Supportセクションを確認してください big_image_size_thresholdフィルターを無効化(return false)すると、元の巨大な画像がそのまま保存されます。ストレージ容量に注意してください
まとめ
WordPress画像最適化の解決は①wp_get_image_editor()でGD/ImageMagick確認・WebPサポート状況・PHPメモリ制限の確認、②WP_MEMORY_LIMIT=256M設定・jpeg_qualityフィルターで画質調整・big_image_size_thresholdで最大サイズ制限、③wp media regenerateで全サムネイル再生成・add_image_size()でカスタムサイズ登録・intermediate_image_sizes_advancedで不要サイズ削除、④wp_generate_attachment_metadataフックでWebP自動生成・wp_calculate_image_srcsetにWebP追加・picture要素でフォールバック配信、⑤loading=lazy・decoding=async・width/height属性でCLS防止・アイキャッチにfetchpriority=highでLCP改善の手順で解決します。