パソコン情報

AI(Gemini)にWordPressの記事を生成してもらうプラグインを作成

WordePressのプラグインを自作できる時代

まったくWordPressのプラグイン作成知識のない自分が、

ココがポイント

AIを使ってWordPressのプラグインを作成できる!

時代になりました。初めてやってみましたが、本当に驚きです。

作成手順

  1. AIに指示をして欲しいプラグインのPHPで生成
  2. ホルダーの中にPHPファイルを入れて圧縮
  3. プラグインを追加して有効化する

上記の手順を追って実際にやってみたいと思います。

 

AI Chatを使ってプラグインを生成

AIの方は、何でもよかったのですが、ChatGPTだとおもって契約したサービスが、AI Chatという有料版だったので、使わないのは勿体ないので、これをつかいました。

https://pctips.jp/ai/chatgpt-pro-review-free-vs-paid/

実際は、Geminiでも、Copilotでも無料版で余裕で同じ事ができます。

さて、指示したプロンプトは、

参考

(1)Wordpressでブログを書いていますが、自動で記事情報を収集して下書きしてくれる方法を教えて

(2)Gemini APIキーで作成する方法ないの?

という流れから、AIが、プラグインを作成してくれる流れとなりました。

PHPでコードをかいてくれるのはいいのですが、初心者なので、そのコードをどのようにしてプラグインにするのかが分かっていませんでした。

そこで、AIに、どのようにプラグインをインストールするのか?を聞くとフォルダーの中(ai-article-generator)に、PHPファイル(ai-article-generator.zip)を入れて圧縮してアップロードすればいいという流れを教えてもらいました。

ココに注意

実際にアップロードをして有効化するとエラーの嵐でした!

そのエラーをAIに流して、コードを修正してもらってアップロードして有効化してを繰り返しました。

そのうち、エラーが無くなり、GeminiのAPIキーを入力して、記事作成までいきました。

※GeminiのAPIキーは無料で取得できます。

しかし、またエラーがでましたので、AIに流してコードを修正しての繰り返しをしました。

そして、動くようになったコードが下記になります。

<?php
/*
Plugin Name: AI Article Generator Meta Fix
Plugin URI: https://pctips.jp/
Description: 管理画面からテーマを入力するだけで、Gemini APIを使ってSEOメタデータ付きの記事を自動生成・下書き保存するプラグイン。
Version: 1.8
Author: Your Name
License: GPL2
*/

if (!defined('ABSPATH')) {
    exit;
}

/**
 * 1. 管理画面にメニューを追加
 */
add_action('admin_menu', 'ai_generator_add_menu');
function ai_generator_add_menu() {
    add_menu_page(
        'AI記事生成',            // ページタイトル
        'AI記事生成',            // メニュータイトル
        'manage_options',        // 権限
        'ai-article-generator',  // メニュースラッグ
        'ai_generator_admin_page', // 表示用関数
        'dashicons-welcome-write-blog', // アイコン
        6                        // 表示位置
    );
}

/**
 * 2. プロンプト生成関数
 */
function get_ai_seo_prompt($topic) {
    $template = <<<PROMPT
以下のテーマについて、SEOに最適化されたブログ記事データを、指定のフォーマットに完全に従って生成してください。

【出力フォーマット】
---START_SEO---
TITLE: ここにSEOタイトル
META_DESCRIPTION: ここにメタディスクリプション(120?160文字)
META_KEYWORDS: キーワード1, キーワード2, キーワード3
TAGS: タグ1, タグ2, タグ3
---END_SEO---

---START_BODY---
<h1>大見出し(記事タイトル)</h1>
<p>導入文</p>
<h2>中見出し</h2>
<p>本文</p>
<h3>小見出し</h3>
<p>本文</p>
<h2>まとめの見出し</h2>
<p>まとめの本文</p>
---END_BODY---

【重要ルール】
1. 上記のフォーマット(---で囲まれた境界線やラベル)を絶対に崩さず、そのまま出力してください。
2. フォーマット以外の挨拶、解説、補足説明は「一切」出力しないでください。
3. Markdown(#、##、###、**など)は絶対に、いかなる場所にも使用しないでください。
4. 本文(BODY)は、必ずHTMLタグ(<h1>, <h2>, <h3>, <p>など)のみで構成してください。
5. META_DESCRIPTION と META_KEYWORDS は絶対に省略せず、指定の場所に必ず出力してください。

テーマ:{$topic}
PROMPT;
    return $template;
}

/**
 * 3. Gemini APIへの通信処理(エラー対策の完全版)
 * - v1betaエンドポイント使用、ペイロードは contentsのみ
 * - テキストは parts 配列配下の text に格納して送信
 * - model 名称は ListModels で返ってくる形式を考慮した正規化を実装
 */
function call_gemini_api($prompt, $api_key, $model = 'gemini-1.5-flash') {
    if (empty($api_key)) {
        return new WP_Error('missing_key', 'APIキーが設定されていません。');
    }

    // モデル名の正規化
    $model_input = trim($model);
    if (strpos($model_input, 'models/') === 0) {
        $model_name = substr($model_input, strlen('models/'));
    } else {
        $model_name = $model_input;
    }

    // v1beta エンドポイント
    $url = 'https://generativelanguage.googleapis.com/v1beta/models/' . urlencode($model_name) . ':generateContent?key=' . $api_key;
    
    // v1beta の正しいペイロード(contents 配列の中に parts[0].text として送信)
    $body = array(
        'contents' => array(
            array(
                'parts' => array(
                    array(
                        'text' => $prompt
                    )
                )
            )
        )
    );

    $args = array(
        'body'        => json_encode($body),
        'headers'     => array(
            'Content-Type' => 'application/json', // ヘッダーを厳密に指定
        ),
        'timeout'     => 120, // 記事生成の待ち時間を2分に設定
    );

    // WordPressのHTTP APIを使用してPOSTリクエストを送信
    $response = wp_remote_post($url, $args);

    if (is_wp_error($response)) {
        return $response;
    }

    $code = wp_remote_retrieve_response_code($response);
    $response_body = wp_remote_retrieve_body($response);

    // ステータスコードが200以外の場合は詳細なエラーを返す
    if ($code !== 200) {
        return new WP_Error('api_error', 'Gemini APIエラーが発生しました。Code: ' . $code . ' / Message: ' . $response_body);
    }

    $data = json_decode($response_body, true);
    
    // レスポンスからテキスト部分を安全に抽出
    if (isset($data['candidates'][0]['content']['parts'][0]['text'])) {
        return $data['candidates'][0]['content']['parts'][0]['text'];
    }
    if (isset($data['candidates'][0]['content']['text'])) {
        return $data['candidates'][0]['content']['text'];
    }
    if (isset($data['candidates'][0]['text'])) {
        return $data['candidates'][0]['text'];
    }
    if (isset($data['candidates'][0]['output']['text'])) {
        return $data['candidates'][0]['output']['text'];
    }

    return new WP_Error('parse_error', 'APIからの返答データが空、または解析できませんでした。');
}

/**
 * 4. テキスト解析&WordPress投稿挿入
 */
function insert_ai_generated_post($response_text, $post_status = 'draft') {
    $title            = '';
    $meta_description = '';
    $meta_keywords    = '';
    $tags             = '';
    $body_content     = '';

    if (preg_match('/TITLE:\s*(.*)/i', $response_text, $matches)) {
        $title = sanitize_text_field(trim($matches[1]));
    }
    if (preg_match('/META_DESCRIPTION:\s*(.*)/i', $response_text, $matches)) {
        $meta_description = sanitize_text_field(trim($matches[1]));
    }
    if (preg_match('/META_KEYWORDS:\s*(.*)/i', $response_text, $matches)) {
        $meta_keywords = sanitize_text_field(trim($matches[1]));
    }
    if (preg_match('/TAGS:\s*(.*)/i', $response_text, $matches)) {
        $tags = sanitize_text_field(trim($matches[1]));
    }
    if (preg_match('/---START_BODY---\s*(.*?)\s*---END_BODY---/s', $response_text, $matches)) {
        $body_content = wp_kses_post(trim($matches[1]));
    } else {
        $body_content = wp_kses_post($response_text);
    }

    if (empty($title)) {
        $title = 'AI生成記事_' . current_time('Ymd_His');
    }

    $post_data = array(
        'post_title'   => $title,
        'post_content' => $body_content,
        'post_status'  => $post_status,
        'post_type'    => 'post',
        'tags_input'   => $tags,
    );

    $post_id = wp_insert_post($post_data);

    if (is_wp_error($post_id) || $post_id === 0) {
        return false;
    }

    // 各種SEOプラグインのカスタムフィールドへ保存
    if (!empty($meta_description)) {
        update_post_meta($post_id, '_aioseo_description', $meta_description); // All in One SEO
        update_post_meta($post_id, 'aioseo_description', $meta_description);
        update_post_meta($post_id, 'rank_math_description', $meta_description); // Rank Math
        update_post_meta($post_id, '_yoast_wpseo_metadesc', $meta_description); // Yoast SEO
    }
    if (!empty($meta_keywords)) {
        update_post_meta($post_id, '_aioseo_keywords', $meta_keywords); // All in One SEO
        update_post_meta($post_id, 'aioseo_keywords', $meta_keywords);
        update_post_meta($post_id, 'rank_math_focus_keyword', $meta_keywords); // Rank Math
    }

    // タイトルのSEOプラグイン側の設定も可能な限り同期
    if (!empty($title)) {
        // Yoast
        update_post_meta($post_id, '_yoast_wpseo_title', $title);
        // All in One SEO
        update_post_meta($post_id, '_aioseo_title', $title);
        update_post_meta($post_id, 'aioseo_title', $title);
        // Rank Math
        update_post_meta($post_id, 'rank_math_title', $title);
        update_post_meta($post_id, '_rank_math_title', $title);
    }

    return $post_id;
}

/**
 * 5. 管理画面のGUI表示・処理
 */
function ai_generator_admin_page() {
    if (!current_user_can('manage_options')) {
        return;
    }

    // 設定の保存処理(Gemini APIキー)
    // 追加: Geminiモデル名の保存も同時に行います
    if (isset($_POST['save_settings']) && check_admin_referer('ai_gen_settings_verify')) {
        $api_key = sanitize_text_field($_POST['gemini_api_key']);
        update_option('ai_gen_gemini_api_key', $api_key);

        $model = sanitize_text_field($_POST['gemini_model']);
        update_option('ai_gen_gemini_model', $model);

        echo '<div class="updated"><p>Gemini API設定を保存しました。</p></div>';
    }

    // 記事生成の実行処理
    $message = '';
    if (isset($_POST['generate_post']) && check_admin_referer('ai_gen_execute_verify')) {
        $topic = sanitize_text_field($_POST['article_topic']);
        $api_key = get_option('ai_gen_gemini_api_key');
        $model = get_option('ai_gen_gemini_model', 'gemini-1.5-flash');

        if (empty($topic)) {
            $message = '<div class="error"><p>テーマを入力してください。</p></div>';
        } elseif (empty($api_key)) {
            $message = '<div class="error"><p>先にGemini APIキーを設定・保存してください。</p></div>';
        } else {
            $prompt = get_ai_seo_prompt($topic);
            $ai_response = call_gemini_api($prompt, $api_key, $model);

            if (is_wp_error($ai_response)) {
                $message = '<div class="error"><p>生成失敗: ' . esc_html($ai_response->get_error_message()) . '</p></div>';
            } else {
                $post_id = insert_ai_generated_post($ai_response, 'draft');
                if ($post_id) {
                    $edit_link = get_edit_post_link($post_id);
                    $message = '<div class="updated"><p>記事の作成に成功しました!『下書き』として保存されています。<a href="' . esc_url($edit_link) . '" target="_blank">記事を編集・確認する</a></p></div>';
                } else {
                    $message = '<div class="error"><p>WordPressへの投稿保存に失敗しました。</p></div>';
                }
            }
        }
    }

    $current_api_key = get_option('ai_gen_gemini_api_key', '');
    $current_model   = get_option('ai_gen_gemini_model', 'gemini-1.5-flash');
    ?>

    <div class="wrap">
        <h1>AI記事自動生成パネル (Gemini API / SEOメタ対応版)</h1>
        <?php echo $message; ?>

        <div style="background: #fff; padding: 20px; margin-top: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
            <h2>1. Gemini API接続設定</h2>
            <form method="post" action="">
                <?php wp_nonce_field('ai_gen_settings_verify'); ?>
                <table class="form-table">
                    <tr>
                        <th scope="row"><label for="gemini_api_key">Gemini APIキー</label></th>
                        <td>
                            <input name="gemini_api_key" type="password" id="gemini_api_key" value="<?php echo esc_attr($current_api_key); ?>" class="large-text" placeholder="AIzaSy..." />
                            <p class="description">Google AI Studioで発行したGeminiのAPIキー(AIzaSyから始まる文字列)を入力してください。</p>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><label for="gemini_model">Geminiモデル名</label></th>
                        <td>
                            <input name="gemini_model" type="text" id="gemini_model" value="<?php echo esc_attr($current_model); ?>" class="regular-text" placeholder="gemini-1.5-flash" />
                            <p class="description">ListModelsで表示されるモデルIDを入力してください。例: gemini-1.5-flash または gemini-2.5-flash。入力値は正規化されます。</p>
                        </td>
                    </tr>
                </table>
                <p class="submit">
                    <input type="submit" name="save_settings" id="save_settings" class="button button-primary" value="設定を保存する">
                </p>
            </form>
        </div>

        <div style="background: #fff; padding: 20px; margin-top: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
            <h2>2. 記事自動生成</h2>
            <form method="post" action="">
                <?php wp_nonce_field('ai_gen_execute_verify'); ?>
                <table class="form-table">
                    <tr>
                        <th scope="row"><label for="article_topic">記事のテーマ・キーワード</label></th>
                        <td>
                            <input name="article_topic" type="text" id="article_topic" value="" class="large-text" placeholder="例: バイクツーリングで外せない栃木のおすすめキャンプ場5選" />
                            <p class="description">生成したいブログ記事の具体的なキーワードやテーマを入力します。</p>
                        </td>
                    </tr>
                </table>
                <p class="submit">
                    <input type="submit" name="generate_post" id="generate_post" class="button button-hero button-primary" value="Geminiで記事を生成する (下書き保存)">
                </p>
            </form>
        </div>
    </div>
    <?php
}

 

実際に使ってみる

APIキーを入力して、Geminiモデル名を入力して、「設定を保存する」をしました。

次に、記事のテーマ・キーワードを入力して、「Geminiで記事を生成する(下書き保存)」をクリックすると、約1分程度で下書きを生成することに成功しました。

ただ、「titleタグ」「メタキーワード」「メタディスクリプション」の部分が空だったので、なんどもAIにコードを修正してもらいましたが、うまくいきませんでした。

しかし、下の方にカスタムフィールドと言う部分があり、その部分には出力されていました。つまり、SEOプラグイン関係で何かうまくいかないことがあるようでした。

でも、コピペの手間だけなので今回は良しとしました。

 

画像挿入は手動

本当なら、完全自動化にて、AIエージェントを動かして作業したいところですが、自分のスキルが付いていってないので、今回は負担を減らす事だけに集中しました。

そんため、画像も手動となりますが、なかなか記事にあった画像を探すのに時間がかかります。

そこで、AI Chatを使って画像は生成することにしました。

これで欲しい画像も数分で入手することが可能となりました。

本当に便利な時代になりました。

今まで、半日かかっていたブログ記事が、この機能を使うことで、1時間程度に短縮することが可能となりました。