php初心者のなのたんがWordpressプラグインをChatGPTで1時間ちょいで作るの巻き

## はじめに

やりたいことはこれ

nginx + fpmの環境で無料でwebp、AVIFに圧縮できない

このサイトで使うものなのね

https://blog.773.moe/

ないものは作ってしまおうなの、ってことで
[ChatGPT](https://apps.microsoft.com/detail/9nt1r1c2hh7j?hl=ja-jp&gl=US) というWindowsアプリを起動

確かにWordpressテーマは作ったものの、プラグインははじめて
## 最初のステップ

> Wordpressのプラグインの作り方

1. プラグインのフォルダとファイルを作成
まず、wp-content/plugins/ ディレクトリに移動し、新しいフォルダを作ります。例えば my-custom-plugin というフォルダを作成。
その中に my-custom-plugin.php というファイルを作成します。

```php
<?php
/**
 * Plugin Name: My Custom Plugin
 * Plugin URI:  https://example.com/
 * Description: シンプルなカスタムプラグイン
 * Version:     1.0
 * Author:      あなたの名前
 * Author URI:  https://example.com/
 * License:     GPL2
 *```
```

2. 基本的なフックを追加
WordPressの動作をカスタマイズするためにフック（Hook）を使います。

(1) メニューに設定ページを追加
管理画面のメニューに新しい項目を追加するには add_menu_page() を使います。

```php
function my_plugin_menu() {
    add_menu_page(
        'My Plugin Settings',   // ページタイトル
        'My Plugin',            // メニュータイトル
        'manage_options',       // 権限
        'my-plugin',            // メニューのスラッグ
        'my_plugin_settings'    // 表示する関数
    );
}

function my_plugin_settings() {
    echo '<h1>My Plugin Settings</h1>';
    echo '<p>ここに設定を追加できます。</p>';
}

add_action('admin_menu', 'my_plugin_menu');
```

他にもショートコードとかajaxとか紹介してくれるのですが、今回使わない

最後に

>どんなプラグインを作りたいですか？ 具体的な機能が決まっていれば、それに合わせたコードを用意できますよ！

というわけで、言ってみました

## まずコードを出させる

>nginx+fpmの環境でWordpressを使用時、mod_rewriteが使えない環境での
>webp画像変換
>キャッシュ系プラグインをOFFにした前提で
>Accpect webpヘッダを確認して、自サーバー分の画像の自動的に出力したHTMLをfilename.jpg.webpとかにして
>出力したい、もしくは
>JavaScriptを用いてリライトをしたい
>リライトがなくなることでApacheでもリライト分の遅延がなくなると思う


そうしたらこうなりました

Nginx + PHP-FPM 環境で mod_rewrite を使わずに WebP 画像を配信する方法

Apache の mod_rewrite を使わずに WebP 画像を配信する方法には、大きく分けて以下の2つのアプローチがあります。

Nginx で Accept ヘッダーをチェックし、WebP を直接配信する
JavaScript を使い、クライアント側で WebP 画像を差し替える
キャッシュ系プラグインが無効になっている前提で、どちらの方法でも WebP 画像を優先的に配信できます。

> 方法 1: Nginx で WebP 画像を配信
無視

> 方法 2: JavaScript を使って WebP に置き換える
候補

というわけで

どちらの方法で進めたいですか？また、WebP 画像の生成も自動化したいですか？

>nginx.confとかの設定をなしに何もかも自動化したい

その答えはこれでした

① プラグインで画像アップロード時に WebP を自動生成
```php
function generate_webp_on_upload($metadata) {
    $upload_dir = wp_upload_dir();
    $base_dir = $upload_dir['basedir'];

    foreach ($metadata['sizes'] as $size) {
        $file_path = $base_dir . '/' . $size['file'];
        $webp_path = $file_path . '.webp';

        if (!file_exists($webp_path) && function_exists('imagewebp')) {
            $image = imagecreatefromstring(file_get_contents($file_path));
            if ($image) {
                imagewebp($image, $webp_path, 80); // 80は圧縮率（0～100）
                imagedestroy($image);
            }
        }
    }
    return $metadata;
}
add_filter('wp_generate_attachment_metadata', 'generate_webp_on_upload');

```

② 出力する HTML の <img> を自動で WebP に置換
```php
function replace_images_with_webp($content) {
    if (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false) {
        $content = preg_replace('/\.(jpg|jpeg|png)/i', '.${1}.webp', $content);
    }
    return $content;
}
add_filter('the_content', 'replace_images_with_webp');

```

③ JavaScript で WebP に置き換える

```JavaScript
document.addEventListener("DOMContentLoaded", function () {
    if (!document.createElement("canvas").toDataURL("image/webp").startsWith("data:image/webp")) {
        return;
    }

    document.querySelectorAll("img").forEach((img) => {
        if (img.src.match(/\.(jpg|jpeg|png)$/)) {
            let webpSrc = img.src + ".webp";

            let xhr = new XMLHttpRequest();
            xhr.open("HEAD", webpSrc, true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    img.src = webpSrc;
                }
            };
            xhr.send();
        }
    });
});
```

このもとから

```php:webp-converter.php
<?php
/**
 * Plugin Name: WebP Converter
 * Description: 自動で WebP を作成し、HTML を変換する
 * Version: 1.0
 * Author: あなたの名前
 */

function generate_webp_on_upload($metadata) {
    $upload_dir = wp_upload_dir();
    $base_dir = $upload_dir['basedir'];

    foreach ($metadata['sizes'] as $size) {
        $file_path = $base_dir . '/' . $size['file'];
        $webp_path = $file_path . '.webp';

        if (!file_exists($webp_path) && function_exists('imagewebp')) {
            $image = imagecreatefromstring(file_get_contents($file_path));
            if ($image) {
                imagewebp($image, $webp_path, 80);
                imagedestroy($image);
            }
        }
    }
    return $metadata;
}
add_filter('wp_generate_attachment_metadata', 'generate_webp_on_upload');

function replace_images_with_webp($content) {
    if (strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false) {
        $content = preg_replace('/\.(jpg|jpeg|png)/i', '.${1}.webp', $content);
    }
    return $content;
}
add_filter('the_content', 'replace_images_with_webp');

function webp_converter_enqueue_script() {
    wp_enqueue_script('webp-converter', plugin_dir_url(__FILE__) . 'webp-converter.js', array(), null, true);
}
add_action('wp_enqueue_scripts', 'webp_converter_enqueue_script');
```

```JavaScript:webp-converter.js
document.addEventListener("DOMContentLoaded", function () {
    if (!document.createElement("canvas").toDataURL("image/webp").startsWith("data:image/webp")) {
        return;
    }

    document.querySelectorAll("img").forEach((img) => {
        if (img.src.match(/\.(jpg|jpeg|png)$/)) {
            let webpSrc = img.src + ".webp";

            let xhr = new XMLHttpRequest();
            xhr.open("HEAD", webpSrc, true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    img.src = webpSrc;
                }
            };
            xhr.send();
        }
    });
});
```

ができました

## 欲がだんだん出てくる

>プラグイン設定画面を作る（画質調整や書き換えの ON/OFF を設定可能にする）
>既存の画像も WebP に変換する機能を追加（バッチ処理）

>のコードは？

とかしていくがどんどん出力してくれます

```php:buggy-autoconvert.php
// 一括変換のボタンを追加
function webp_converter_add_bulk_convert_button() {
    ?>
    <form method="post" action="">
        <input type="hidden" name="webp_bulk_convert" value="1">
        <?php submit_button('既存画像を WebP に変換'); ?>
    </form>
    <?php
    if (isset($_POST['webp_bulk_convert'])) {
        webp_convert_existing_images();
    }
}
add_action('admin_notices', 'webp_converter_add_bulk_convert_button');

// 既存画像を WebP に変換
function webp_convert_existing_images() {
    $upload_dir = wp_upload_dir();
    $base_dir = $upload_dir['basedir'];
    $files = glob($base_dir . '/**/*.{jpg,jpeg,png}', GLOB_BRACE);

    if (!$files) {
        echo '<div class="notice notice-error"><p>変換する画像が見つかりません。</p></div>';
        return;
    }

    $quality = get_option('webp_quality', 80);
    $converted_count = 0;

    foreach ($files as $file) {
        $webp_path = $file . '.webp';

        if (!file_exists($webp_path) && function_exists('imagewebp')) {
            $image = imagecreatefromstring(file_get_contents($file));
            if ($image) {
                imagewebp($image, $webp_path, $quality);
                imagedestroy($image);
                $converted_count++;
            }
        }
    }

    echo '<div class="notice notice-success"><p>' . $converted_count . ' 件の画像を WebP に変換しました。</p></div>';
}
```

これが動かなかったのです

> 既存画像をWebpに変換ボタンを押したら、変換する画像が見つかりません、と出た

として

✅ 1. glob() のパスが間違っている
現在のコードでは glob() を使って wp-content/uploads/ 以下の画像を探しています。
しかし、以下の問題で画像が見つからないことがあります。

wp_upload_dir() の basedir が 正しく取得できていない
glob() の 検索パターンが間違っている
画像の拡張子が .JPG など 大文字 で保存されている
🔹 修正コード（glob() の検索パスを修正）

```php
function webp_convert_existing_images() {
    $upload_dir = wp_upload_dir();
    $base_dir = $upload_dir['basedir']; // 例: /home/username/public_html/wp-content/uploads
    $quality = get_option('webp_quality', 80);

    // 再帰的に検索し、すべての jpg/jpeg/png を取得（大文字・小文字対応）
    $files = glob($base_dir . '/**/*.{jpg,jpeg,png,JPG,JPEG,PNG}', GLOB_BRACE);

    if (!$files) {
        echo '<div class="notice notice-error"><p>変換する画像が見つかりません。フォルダや拡張子を確認してください。</p></div>';
        return;
    }

    $converted_count = 0;

    foreach ($files as $file) {
        $webp_path = $file . '.webp';

        if (!file_exists($webp_path) && function_exists('imagewebp')) {
            $image = imagecreatefromstring(file_get_contents($file));
            if ($image) {
                imagewebp($image, $webp_path, $quality);
                imagedestroy($image);
                $converted_count++;
            }
        }
    }

    echo '<div class="notice notice-success"><p>' . $converted_count . ' 件の画像を WebP に変換しました。</p></div>';
}
```

で、治ったのです

たまにバグ出すコードを出すのでプチ怒りするのですが
何かといってできた一番最初のコードはこれになるの

https://github.com/nanakochi123456/Neo-Webp-AVIF-Converter-for-Wordpress/commit/df4aa273ef701bbf5631a67af38bed235c5d8332

ここまで1時間強
このコードはちゃんと動きました

## もっと欲をつけて、まぁまぁ出来上がり

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149448/160095b6-c46b-4a56-9550-c39cbda324fe.png)

割と使えるツールになってきました
ただ、avif変換の枚数が多いと504になるものの

https://github.com/nanakochi123456/Neo-Webp-AVIF-Converter-for-Wordpress

Wordpressプラグインディレクトリに掲載されるのを目標に
まったりと行こうかと思います

# また作ってしまった
記事を何分で読めるか？というプラグインがあるけど
なにかといってめんどくさいの

というわけでまたChatGPTにお願いしたの

>Wordpressのプラグインを作ってほしいの
>記事ページすべての先頭に
>「この記事は何分何秒で読めます」
>と表示させたい
>300文字で1分とカウントしたい

無意味に秒までカウントさせるの


しかし、初版は明らかにHTMLの中身までカウントしていたので
修正させたのが、以下です

https://github.com/nanakochi123456/Neo-Reading-Time-Display