2026年10月8日

2026年10月8日

WordPressのキャッシュエラーを解決する方法

はじめに

WordPressの投稿を更新してもサイトに反映されずに古いコンテンツが表示され続ける・キャッシュプラグインを有効にすると一部のページでレイアウトが崩れる・ログインユーザーにもキャッシュされたページが表示されてマイアカウントページが正しく表示されない・Redisをインストールしたがオブジェクトキャッシュが機能していないといった問題は、キャッシュの設定ミス・除外ルールの不備・パーミッションの問題が原因です。

症状・原因

  • 投稿を公開・更新しても数分経ってもサイトに反映されない
  • WooCommerceのカートページでキャッシュされた他ユーザーのカート情報が表示される
  • wp-content/cache/ディレクトリへの書き込み権限がなくキャッシュが生成されない
  • object-cache.phpがwp-content/に配置されているがRedisに接続できない

解決手順

ステップ1:キャッシュの状態を診断する

# WP-CLIでキャッシュの状態を確認
wp cache flush
wp eval "
echo 'Object cache: '  . (wp_using_ext_object_cache() ? 'external (Redis/Memcached)' : 'internal') . PHP_EOL;
echo 'Cache dir: '     . WP_CONTENT_DIR . '/cache/' . PHP_EOL;
echo 'Cache writable: ' . (is_writable(WP_CONTENT_DIR . '/cache/') ? 'yes' : 'NO') . PHP_EOL;
"

# Redisの接続を確認
wp eval "
if (class_exists('Redis')) {
    try {
        \$redis = new Redis();
        \$redis->connect('127.0.0.1', 6379);
        echo 'Redis connected: ' . \$redis->ping() . PHP_EOL;
        echo 'Redis memory: ' . \$redis->info('memory')['used_memory_human'] . PHP_EOL;
    } catch (Exception \$e) {
        echo 'Redis error: ' . \$e->getMessage() . PHP_EOL;
    }
}
"

# キャッシュディレクトリのサイズ
wp eval "
\$cache_dir = WP_CONTENT_DIR . '/cache/';
if (is_dir(\$cache_dir)) {
    \$size = 0;
    \$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(\$cache_dir));
    foreach (\$files as \$file) { if (\$file->isFile()) \$size += \$file->getSize(); }
    echo 'Cache size: ' . number_format(\$size / 1024 / 1024, 2) . ' MB' . PHP_EOL;
}
"

ステップ2:ページキャッシュを正しく設定する

// wp-config.php: キャッシュ設定
define('WP_CACHE', true);  // キャッシュプラグインを有効化するために必要

// advanced-cache.php が wp-content/ に必要(キャッシュプラグインが自動設置)
// functions.php: キャッシュの除外ルール設定

// ① ログインユーザーのキャッシュを除外
add_action('init', function(): void {
    if (is_user_logged_in()) {
        // キャッシュプラグインにキャッシュしないよう指示
        if (!defined('DONOTCACHEPAGE')) {
            define('DONOTCACHEPAGE', true);
        }
    }
});

// ② 特定のページをキャッシュから除外
add_action('template_redirect', function(): void {
    $exclude_pages = [
        wc_get_page_id('cart'),
        wc_get_page_id('checkout'),
        wc_get_page_id('myaccount'),
    ];

    if (class_exists('WooCommerce') && in_array(get_the_ID(), $exclude_pages, true)) {
        if (!defined('DONOTCACHEPAGE')) {
            define('DONOTCACHEPAGE', true);
        }
        // HTTPヘッダーでキャッシュを禁止
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
        header('Expires: 0');
    }
});

// ③ 投稿更新時にキャッシュを自動クリア
add_action('save_post', function(int $post_id): void {
    if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
        return;
    }
    wp_cache_flush();

    // W3 Total Cache
    if (function_exists('w3tc_flush_post')) {
        w3tc_flush_post($post_id);
    }
    // WP Super Cache
    if (function_exists('wp_cache_post_change')) {
        wp_cache_post_change($post_id);
    }
    // LiteSpeed Cache
    if (class_exists('LiteSpeed_Cache_API')) {
        LiteSpeed_Cache_API::purge_post($post_id);
    }
});

ステップ3:オブジェクトキャッシュを設定する

// wp-content/object-cache.php: シンプルなRedisオブジェクトキャッシュ
// (Redis Object Cache プラグインが自動設置するファイルの簡略版)

// wp-config.php に追加:
// define('WP_REDIS_HOST', '127.0.0.1');
// define('WP_REDIS_PORT', 6379);
// define('WP_REDIS_TIMEOUT', 1);
// define('WP_REDIS_READ_TIMEOUT', 1);
// define('WP_REDIS_DATABASE', 0);
# Redisのインストールと設定確認
redis-cli ping  # PONG が返れば正常

# WordPress用のRedis設定確認
wp eval "
\$result = wp_cache_get('test_key', 'test_group');
if (\$result === false) {
    wp_cache_set('test_key', 'test_value', 'test_group', 60);
    \$result = wp_cache_get('test_key', 'test_group');
    echo 'Cache set/get test: ' . (\$result === 'test_value' ? 'PASS' : 'FAIL') . PHP_EOL;
}
"

# Redisのキャッシュ使用状況
wp redis info 2>/dev/null || echo "Redis plugin not active"

ステップ4:トランジェントキャッシュを活用する

// functions.php: トランジェントを使った効果的なキャッシュ

// ① APIレスポンスをキャッシュ
function get_cached_api_data(string $endpoint): array {
    $cache_key = 'api_data_' . md5($endpoint);
    $cached    = get_transient($cache_key);

    if (false !== $cached) {
        return $cached;
    }

    $response = wp_remote_get($endpoint, ['timeout' => 10]);

    if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
        return [];
    }

    $data = json_decode(wp_remote_retrieve_body($response), true) ?? [];
    set_transient($cache_key, $data, HOUR_IN_SECONDS);
    return $data;
}

// ② 重いデータベースクエリをキャッシュ
function get_popular_posts(int $count = 5): array {
    $cache_key = "popular_posts_{$count}";
    $cached    = wp_cache_get($cache_key, 'popular_posts');

    if (false !== $cached) {
        return $cached;
    }

    $posts = get_posts([
        'posts_per_page' => $count,
        'meta_key'       => 'post_views_count',
        'orderby'        => 'meta_value_num',
        'order'          => 'DESC',
    ]);

    wp_cache_set($cache_key, $posts, 'popular_posts', 30 * MINUTE_IN_SECONDS);
    return $posts;
}

// ③ キャッシュの統計情報を取得
add_action('wp_footer', function(): void {
    if (!current_user_can('manage_options') || !WP_DEBUG) {
        return;
    }
    global $wpdb;
    printf(
        '<!-- DB queries: %d | Query time: %.4fs | Memory: %s -->',
        $wpdb->num_queries,
        timer_stop(0, 4),
        size_format(memory_get_peak_usage(true))
    );
});

ステップ5:ブラウザキャッシュとHTTPヘッダーを設定する

# .htaccess: ブラウザキャッシュの設定
<IfModule mod_expires.c>
    ExpiresActive On

    # 画像ファイル(1年)
    ExpiresByType image/jpeg  "access plus 1 year"
    ExpiresByType image/png   "access plus 1 year"
    ExpiresByType image/webp  "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"

    # CSSとJavaScript(1ヶ月)
    ExpiresByType text/css                "access plus 1 month"
    ExpiresByType application/javascript  "access plus 1 month"

    # フォント(1年)
    ExpiresByType font/woff2  "access plus 1 year"
    ExpiresByType font/woff   "access plus 1 year"
</IfModule>

<IfModule mod_headers.c>
    # キャッシュ済みリソースのバリデーション
    <FilesMatch "\.(css|js|png|jpg|webp|woff2)$">
        Header append Cache-Control "public, immutable"
    </FilesMatch>
</IfModule>

注意事項

  • DONOTCACHEPAGE定数はWP Super CacheとW3 Total Cacheが認識しますが、全てのキャッシュプラグインが対応しているわけではありません。使用しているプラグインのドキュメントで除外方法を確認してください
  • ログインユーザーとWooCommerceのカート・マイアカウントページは必ずキャッシュから除外してください。キャッシュされると他のユーザーの個人情報が表示される重大なセキュリティ問題が発生します
  • Redisのオブジェクトキャッシュを使用する場合、サーバーが再起動するとキャッシュが消えます。maxmemory-policyをallkeys-lruに設定してメモリが満杯になった場合の動作を定義してください

まとめ

WordPressキャッシュエラーの解決は①wp_using_ext_object_cache()でキャッシュ種別確認・cache/ディレクトリの書き込み権限チェック・redis-cli pingでRedis接続確認、②WP_CACHE=trueをwp-config.phpに追加・DONOTCACHEPAGE定数でログインユーザーと動的ページを除外・Cache-Control: no-storeヘッダーで確実にキャッシュ禁止、③save_postフックでw3tc_flush_post/wp_cache_post_change/LiteSpeed_Cache_API::purge_postでプラグイン対応のキャッシュクリア、④wp_cache_get/setでオブジェクトキャッシュ・get_transient/set_transientでAPIレスポンスと重いクエリをキャッシュ、⑤.htaccessのmod_expiresで画像1年・CSS/JS1ヶ月のブラウザキャッシュ設定の手順で解決します。

お気軽にご相談ください

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