WordPressで画像のURLに最終更新日時をクエリパラメータとして追加する方法

WordPressでコンテンツを更新した際に、画像のキャッシュが原因で更新が反映されないことがあります。この問題を解決するため、画像URLに最終更新日時をクエリパラメータとして追加する方法を紹介します。

## 解決したい問題

- WordPressで記事やページを更新しても、ブラウザキャッシュにより画像が更新されない
- 特に、同じファイル名で画像を差し替えた場合に問題が発生
- レスポンシブ対応のsrcset属性を使用している場合も同様の問題が発生

## 解決方法

`functions.php`に以下のコードを追加することで、コンテンツ内の画像URLに最終更新日時をクエリパラメータとして自動的に付加できます。

```php
/* content内の画像URLに、最終更新日時をクエリ文字として追加 */
function add_version_query_to_images($content) {
    global $post;
    $last_modified = $post->post_modified;
    $last_modified_date = new DateTime($last_modified);
    $version = $last_modified_date->format('YmdHis');

    $attributes = array('src', 'data-src0', 'data-src744', 'srcset');
    $site_url = parse_url(get_site_url(), PHP_URL_HOST);

    foreach ($attributes as $attribute) {
        if ($attribute === 'srcset') {
            // srcset属性の処理
            $pattern = '/(<source[^>]*srcset=["\'])([^"\']*)(["\'])/i';
            preg_match_all($pattern, $content, $matches, PREG_SET_ORDER);

            foreach ($matches as $match) {
                $srcset = $match[2];
                $new_srcset = $srcset;

                // カンマで区切られた各URLを処理
                $srcset_urls = explode(',', $srcset);
                foreach ($srcset_urls as $i => $srcset_url) {
                    // URLとサイズ指定を分離
                    $parts = preg_split('/\s+/', trim($srcset_url));
                    $url = $parts[0];

                    // 内部URLの場合のみ処理
                    if (strpos($url, $site_url) !== false || !preg_match('/^https?:\/\//', $url)) {
                        $separator = strpos($url, '?') !== false ? '&' : '?';
                        $new_url = $url . $separator . 'ver=' . $version;
                        // サイズ指定がある場合は保持
                        if (isset($parts[1])) {
                            $new_url .= ' ' . $parts[1];
                        }
                        $srcset_urls[$i] = $new_url;
                    }
                }
                
                // 更新したURLを結合
                $new_srcset = implode(', ', $srcset_urls);
                $content = str_replace($match[2], $new_srcset, $content);
            }
        } else {
            // 通常の画像属性の処理
            $pattern = '/(img[^\>]*' . $attribute . '=["\'])([^"\']*)(["\'])/';
            preg_match_all($pattern, $content, $matches, PREG_SET_ORDER);

            foreach ($matches as $match) {
                $url = $match[2];
                
                if (strpos($url, $site_url) !== false || !preg_match('/^https?:\/\//', $url)) {
                    $separator = strpos($url, '?') !== false ? '&' : '?';
                    $new_url = $url . $separator . 'ver=' . $version;
                    $content = str_replace($match[0], str_replace($url, $new_url, $match[0]), $content);
                }
            }
        }
    }

    return $content;
}
add_filter('the_content', 'add_version_query_to_images');
```

## コードの解説

### 1. 最終更新日時の取得

```php
global $post;
$last_modified = $post->post_modified;
$last_modified_date = new DateTime($last_modified);
$version = $last_modified_date->format('YmdHis');
```

- `global $post`で現在の投稿オブジェクトを取得
- `post_modified`から最終更新日時を取得
- `YmdHis`形式（例：20250130175127）でバージョン文字列を生成

### 2. 処理対象の属性

```php
$attributes = array('src', 'data-src0', 'data-src744', 'srcset');
```

- 通常の`src`属性に加え、遅延読み込み用の`data-src`属性も対象
- レスポンシブ対応用の`srcset`属性も処理

### 3. 内部URLの判定

```php
$site_url = parse_url(get_site_url(), PHP_URL_HOST);
if (strpos($url, $site_url) !== false || !preg_match('/^https?:\/\//', $url))
```

- サイトのドメインを含むURL、または
- `http://`や`https://`で始まらないURL（相対パス）の場合に処理

### 4. srcset属性の特別処理

```php
$srcset_urls = explode(',', $srcset);
foreach ($srcset_urls as $i => $srcset_url) {
    $parts = preg_split('/\s+/', trim($srcset_url));
    $url = $parts[0];
    // ...
}
```

- カンマで区切られた複数のURLに対応
- URLとサイズ指定（例：`2x`や`300w`）を適切に分離して処理

## 使用例と結果

### 通常の画像

```html
<!-- 変更前 -->
<img src="example.jpg" alt="サンプル">

<!-- 変更後 -->
<img src="example.jpg?ver=20250130175127" alt="サンプル">
```

### レスポンシブ画像（srcset使用）

```html
<!-- 変更前 -->
<picture>
  <source srcset="example-sp.jpg" media="(max-width: 743.9px)">
  <img src="example.jpg" alt="">
</picture>

<!-- 変更後 -->
<picture>
  <source srcset="example-sp.jpg?ver=20250130175127" media="(max-width: 743.9px)">
  <img src="example.jpg?ver=20250130175127" alt="">
</picture>
```

## まとめ

- WordPressの画像キャッシュ問題を、URLにバージョンパラメータを追加することで解決
- 内部の画像URLのみを対象とし、外部画像は影響を受けない
- レスポンシブ対応の`srcset`属性にも対応
- 記事の更新日時を自動的に利用するため、手動での管理が不要

この方法により、コンテンツ更新時に確実に新しい画像が表示されるようになり、特にWordPressのテーマ開発やコンテンツ管理の効率が向上します。