2026年5月26日

2026年5月26日

Imagifyのエラーを解決する方法

はじめに

ImagifyでWebP画像の自動生成が有効なのにブラウザにWebPが配信されない・一括最適化を実行すると途中で「タイムアウト」が発生して止まる・月次のAPIクォータ(無料は25MB)を使い切って最適化できない・一度最適化した画像をより高圧縮で再最適化したいといった問題は、サーバーのWebP対応設定・PHPタイムアウト・APIプランの制限が原因です。

症状・原因

  • 「WebP形式でサーブ」を有効にしているがブラウザにはJPEG/PNGが配信される
  • 「全画像を一括最適化」を実行すると30〜50枚で止まり「エラー:タイムアウト」が表示される
  • 新しい画像をアップロードしようとすると「API quota exceeded」エラーが出る
  • 「通常」品質で最適化した画像を「侵略的」品質に変更して再最適化したい

解決手順

ステップ1:Imagifyの状態を確認する

# Imagifyの設定とAPIステータスを確認
wp eval "
// バージョン確認
if (defined('IMAGIFY_VERSION')) {
    echo 'Imagify version: ' . IMAGIFY_VERSION . PHP_EOL;
}

// API設定確認
\$settings = get_imagify_option('api_key', '');
echo 'API key set: ' . (!empty(\$settings) ? 'yes (' . substr(\$settings, 0, 8) . '...)' : 'NO') . PHP_EOL;

// APIステータス確認(クォータ)
try {
    \$user = get_imagify_user();
    if (\$user && !is_wp_error(\$user)) {
        echo 'Plan: '           . (\$user->plan_name ?? 'unknown') . PHP_EOL;
        echo 'Quota used: '     . (\$user->quota_used ?? 0) . ' bytes' . PHP_EOL;
        echo 'Quota total: '    . (\$user->quota ?? 0) . ' bytes' . PHP_EOL;
    }
} catch (Exception \$e) {
    echo 'API check failed: ' . \$e->getMessage() . PHP_EOL;
}

// 最適化統計
\$stats = get_imagify_all_stats();
echo 'Total images optimized: ' . (\$stats['total'] ?? 0) . PHP_EOL;
echo 'Total original size: '    . size_format(\$stats['original_size'] ?? 0) . PHP_EOL;
echo 'Total savings: '          . size_format((\$stats['original_size'] ?? 0) - (\$stats['optimized_size'] ?? 0)) . PHP_EOL;

// WebP設定確認
echo 'WebP: ' . (get_imagify_option('webp') ? 'enabled' : 'disabled') . PHP_EOL;
"

ステップ2:画像最適化をカスタマイズする

// functions.php: Imagify最適化設定

// ① アップロード時の最適化レベルをカスタマイズ
add_filter('imagify_optimization_level', function(int $level, object $process): int {
    // 圧縮レベル: 0=通常, 1=アグレッシブ, 2=侵略的
    // 商品画像は侵略的圧縮(最大圧縮)
    if (get_post_type($process->get_id()) === 'product') {
        return 2;
    }
    return 1; // デフォルトはアグレッシブ
}, 10, 2);

// ② 特定のメディアをImagify最適化から除外
add_filter('imagify_skip_optimization', function(bool $skip, int $attachment_id): bool {
    // SVGはスキップ
    if (get_post_mime_type($attachment_id) === 'image/svg+xml') {
        return true;
    }
    // 2000px未満の小さな画像はスキップ(既に軽量)
    $meta = wp_get_attachment_metadata($attachment_id);
    if (isset($meta['width']) && $meta['width'] < 200) {
        return true;
    }
    return $skip;
}, 10, 2);

// ③ 最適化完了時の処理
add_action('imagify_after_optimize_attachment', function(int $attachment_id, object $process, object $data): void {
    $savings = $data->get_original_size() - $data->get_optimized_size();
    error_log(sprintf('[Imagify] Optimized #%d: saved %s',
        $attachment_id, size_format($savings)));
}, 10, 3);

ステップ3:WebP配信を設定する

// functions.php: WebP配信設定

// ① WebP画像のURLを取得するユーティリティ
function get_webp_url(string $image_url): string {
    if (!function_exists('imagify_get_webp_url')) return $image_url;

    $webp_url = imagify_get_webp_url($image_url);
    return $webp_url ?: $image_url;
}

// ② WebP対応ブラウザにWebPを配信
add_filter('wp_get_attachment_image_src', function(array|false $image, int $attachment_id): array|false {
    if (!$image) return $image;
    if (!function_exists('imagify_get_webp_url')) return $image;

    // Acceptヘッダーでwebp対応確認
    $accept = $_SERVER['HTTP_ACCEPT'] ?? '';
    if (str_contains($accept, 'image/webp')) {
        $webp = imagify_get_webp_url($image[0]);
        if ($webp && $webp !== $image[0]) {
            $image[0] = $webp;
        }
    }
    return $image;
}, 10, 2);

// ③ pictureタグでWebPとフォールバックを提供
function imagify_picture_tag(int $attachment_id, string $size = 'full'): string {
    $src     = wp_get_attachment_image_url($attachment_id, $size);
    $webp    = function_exists('imagify_get_webp_url') ? imagify_get_webp_url($src) : '';
    $alt     = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);

    if ($webp && $webp !== $src) {
        return sprintf(
            '<picture><source srcset="%s" type="image/webp"><img src="%s" alt="%s" loading="lazy"></picture>',
            esc_url($webp), esc_url($src), esc_attr($alt)
        );
    }
    return wp_get_attachment_image($attachment_id, $size);
}

ステップ4:APIクォータの節約と再最適化

// functions.php: APIクォータ管理

// ① APIクォータを確認してから最適化
function safe_imagify_optimize(int $attachment_id): bool {
    if (!function_exists('get_imagify_user')) return false;

    $user = get_imagify_user();
    if (!$user || is_wp_error($user)) return false;

    $quota_remaining = ($user->quota ?? 0) - ($user->quota_used ?? 0);
    $file_size       = filesize(get_attached_file($attachment_id));

    if ($file_size > $quota_remaining) {
        error_log(sprintf('[Imagify] Quota insufficient: need %s, have %s',
            size_format($file_size), size_format($quota_remaining)));
        return false;
    }

    // 最適化を実行
    $process = imagify_get_optimization_process($attachment_id, 'wp');
    $process->optimize(1); // 1 = アグレッシブ
    return true;
}

// ② 最適化済み画像を別レベルで再最適化
function re_optimize_with_level(int $attachment_id, int $level = 2): bool {
    if (!function_exists('imagify_get_optimization_process')) return false;

    $process = imagify_get_optimization_process($attachment_id, 'wp');

    // 既存の最適化データをリセット
    $process->restore();

    // 新しいレベルで再最適化
    $process->optimize($level);
    error_log(sprintf('[Imagify] Re-optimized #%d at level %d', $attachment_id, $level));
    return true;
}

ステップ5:一括最適化のタイムアウト対策

# WP-CLIでバッチ最適化(タイムアウト回避)
wp eval "
// 未最適化の画像を確認
\$unoptimized = get_posts([
    'post_type'      => 'attachment',
    'post_mime_type' => ['image/jpeg', 'image/png', 'image/gif'],
    'posts_per_page' => 20,
    'meta_query'     => [[
        'key'     => '_imagify_status',
        'compare' => 'NOT EXISTS',
    ]],
    'fields' => 'ids',
]);

echo 'Unoptimized images: ' . count(\$unoptimized) . PHP_EOL;

// 1枚ずつ最適化(タイムアウト防止)
\$count = 0;
foreach (array_slice(\$unoptimized, 0, 5) as \$id) {
    if (!function_exists('imagify_get_optimization_process')) break;
    \$process = imagify_get_optimization_process(\$id, 'wp');
    \$process->optimize(1);
    \$count++;
    echo 'Optimized: #' . \$id . PHP_EOL;
}
echo 'Done: ' . \$count . ' images' . PHP_EOL;
"
// functions.php: 一括最適化のタイムアウト対策

// ① バッチサイズを制限
add_filter('imagify_bulk_optimization_images_per_batch', function(int $count): int {
    return 5; // デフォルト10から5に削減
});

// ② タイムアウト時間を延長
add_filter('imagify_request_timeout', function(int $timeout): int {
    return 60; // 60秒(デフォルト30秒)
});

// ③ 最適化エラーをログ
add_action('imagify_after_optimize_attachment', function(int $attachment_id, object $process): void {
    $data = $process->get_data();
    if ($data && $data->get_status() === 'error') {
        error_log(sprintf('[Imagify] Optimization failed for #%d: %s',
            $attachment_id, $data->get_message()));
    }
}, 10, 2);

注意事項

  • ImagifyのWebP配信が機能しない場合、Apacheサーバーでは.htaccessにWebP配信ルールが正しく追加されているか確認してください。NGINXサーバーでは.htaccessは機能しないため、NGINXの設定ファイルに手動でWebPルールを追加する必要があります
  • 無料プランのImagifyはひと月あたり25MB分の画像しか最適化できません。大量の画像を持つサイトでは有料プランへのアップグレードか、ShortPixel・Smush等の代替プラグインの検討をお勧めします。APIクォータは毎月1日にリセットされます
  • 「侵略的」圧縮は画質が若干低下します。商品写真やポートフォリオ画像など品質が重要な画像には「通常」または「アグレッシブ」圧縮を使用し、記事内の補足画像などには「侵略的」圧縮を使用する使い分けが推奨されます

まとめ

Imagify修復は①get_imagify_user()でAPIクォータ確認・get_imagify_all_stats()で最適化統計確認・WebP有効設定の確認、②imagify_optimization_levelフィルターで商品画像に侵略的圧縮を適用・imagify_skip_optimizationフィルターでSVG・小サイズ画像を除外、③wp_get_attachment_image_srcフィルターでAcceptヘッダーを確認してWebP URLに差し替え・タグでフォールバック提供、④safe_imagify_optimize()でクォータ確認後に最適化・restore()optimize(level)で再最適化レベル変更、⑤imagify_bulk_optimization_images_per_batchフィルターでバッチサイズを5に削減・WP-CLIで1枚ずつタイムアウトなし処理する手順で解決します。

お気軽にご相談ください

お見積りへ お問い合わせへ