前回の投稿の続きだよ。

前回で”GASとGemini”、”GASとWordPress”の連携がそれぞれできたから更に組み合わせるよ!

AIに記事を書かせてWordPressに投稿するのが目標。(この記事もほぼAIだけども)

AIと相談しながら書かせたコードがこちら

PHPプラグイン

<?php
/*
Plugin Name: GAS Markdown Publisher
Description: Webアプリから受信したMarkdownファイルを投稿に変換するプラグイン
Version: 1.0
Author: Your Name
*/

// REST APIにカスタムエンドポイントを登録
add_action('rest_api_init', function () {
    register_rest_route('markdown/v1', '/create-post', array(
        'methods' => 'POST', // POSTリクエストを受け付ける
        'callback' => 'create_markdown_post', // リクエスト処理用のコールバック関数
        'permission_callback' => '__return_true', // 全てのリクエストを許可(セキュリティ対策の改善が推奨)
    ));
});

// エンドポイントのリクエストを処理する関数
function create_markdown_post($data) {
    // リクエストから 'content'(本文)と 'title'(タイトル)を取得
    $markdown_content = $data->get_param('content');
    $title = $data->get_param('title');

    // デバッグ用に受信データをログ出力(サーバーのエラーログに記録される)
    error_log('Received title: ' . $title);
    error_log('Received content: ' . $markdown_content);

    // MarkdownをHTMLに変換
    $html_content = markdown_to_html($markdown_content);

    // デフォルト設定を取得(管理画面で設定可能な値)
    $options = get_option('gas_settings');

    // 投稿データを作成
    $new_post = array(
        'post_title'    => !empty($options['gas_text_field_0']) ? $options['gas_text_field_0'] : wp_strip_all_tags($title), // デフォルトタイトルを使用
        'post_content'  => $html_content, // HTMLに変換済みの本文
        'post_status'   => $options['gas_select_field_1'] ?? 'publish', // 投稿ステータス(公開、下書きなど)
        'post_author'   => 2, // 投稿の作成者ID(固定値だがカスタマイズ可能)
        'post_category' => array(1) // カテゴリID(固定値)
    );

    // 投稿をWordPressデータベースに保存
    $post_id = wp_insert_post($new_post);

    // 作成した投稿のIDを返す
    return new WP_REST_Response($post_id, 200);
}

// MarkdownをHTMLに変換する関数
function markdown_to_html($markdown) {
    // Parsedownライブラリを読み込み
    require_once plugin_dir_path(__FILE__) . 'parsedown/Parsedown.php';
    $Parsedown = new Parsedown();
    return $Parsedown->text($markdown); // MarkdownをHTMLに変換
}

// プラグインの設定ページをWordPress管理画面に追加
add_action('admin_menu', 'gas_add_admin_menu');
add_action('admin_init', 'gas_settings_init');

// 管理画面のメニューに設定ページを登録
function gas_add_admin_menu() { 
    add_options_page(
        'GAS Markdown Publisher', // ページタイトル
        'GAS Markdown Publisher', // メニューに表示される名前
        'manage_options', // アクセス権限
        'gas_markdown_publisher', // メニュースラッグ
        'gas_options_page' // ページを描画するコールバック関数
    );
}

// プラグイン設定の初期化
function gas_settings_init() { 
    register_setting('pluginPage', 'gas_settings'); // 設定グループを登録

    // 設定セクションを追加
    add_settings_section(
        'gas_pluginPage_section', 
        __('Settings', 'wordpress'), 
        'gas_settings_section_callback', 
        'pluginPage'
    );

    // デフォルトタイトルの設定フィールドを追加
    add_settings_field( 
        'gas_text_field_0', 
        __('Default Title', 'wordpress'), 
        'gas_text_field_0_render', 
        'pluginPage', 
        'gas_pluginPage_section' 
    );

    // デフォルト投稿ステータスの設定フィールドを追加
    add_settings_field( 
        'gas_select_field_1', 
        __('Default Post Status', 'wordpress'), 
        'gas_select_field_1_render', 
        'pluginPage', 
        'gas_pluginPage_section' 
    );
}

// デフォルトタイトル用の入力フィールドを描画
function gas_text_field_0_render() { 
    $options = get_option('gas_settings');
    ?>
    <input type='text' name='gas_settings[gas_text_field_0]' value='<?php echo $options['gas_text_field_0']; ?>'>
    <?php
}

// デフォルト投稿ステータス用のドロップダウンを描画
function gas_select_field_1_render() { 
    $options = get_option('gas_settings');
    ?>
    <select name='gas_settings[gas_select_field_1]'>
        <option value='publish' <?php selected($options['gas_select_field_1'], 'publish'); ?>>Publish</option>
        <option value='draft' <?php selected($options['gas_select_field_1'], 'draft'); ?>>Draft</option>
        <option value='pending' <?php selected($options['gas_select_field_1'], 'pending'); ?>>Pending</option>
        <option value='private' <?php selected($options['gas_select_field_1'], 'private'); ?>>Private</option>
    </select>
    <?php
}

// 設定ページを描画
function gas_options_page() { 
    ?>
    <form action='options.php' method='post'>
        <h2>GAS Markdown Publisher</h2>
        <?php
        settings_fields('pluginPage'); // 設定グループのフィールドを表示
        do_settings_sections('pluginPage'); // セクションとフィールドを表示
        submit_button(); // 保存ボタンを表示
        ?>
    </form>
    <?php
}

// 設定セクションの説明を描画
function gas_settings_section_callback() { 
    echo __('Markdown投稿のデフォルト設定を構成します。', 'wordpress');
}

// プラグイン一覧ページに設定リンクを追加
add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'gas_settings_link');
function gas_settings_link($links) {
    $settings_link = '<a href="options-general.php?page=gas_markdown_publisher">設定</a>';
    array_unshift($links, $settings_link);
    return $links;
}
?>

簡単な解説

  1. REST APIエンドポイント
    /markdown/v1/create-post エンドポイントを作成し、外部からMarkdown形式のデータを受け取ります。
  2. MarkdownのHTML変換
    Parsedown ライブラリを使用してMarkdownをHTMLに変換します。
  3. 投稿の自動作成
    変換したHTMLコンテンツを使用し、WordPressの wp_insert_post() 関数で投稿をデータベースに保存します。
  4. 管理画面での設定ページ
    デフォルトの投稿タイトルやステータスを設定できるオプションページをWordPressの管理画面に追加します。
  5. プラグインページでのショートカット
    プラグイン一覧に「Settings」リンクを追加して、管理画面の設定ページへ素早くアクセスできるようにしています。

インストール可能なzipはこちら

GAS

// HTMLテンプレート
function doGet() {
  return HtmlService.createHtmlOutputFromFile('index');
}

// 投稿関数
function postMarkdownToWordPress(title, markdownContent) {
  var properties = PropertiesService.getScriptProperties();
  var username = properties.getProperty('user'); // WordPressのユーザー名
  var password = properties.getProperty('pass'); // 生成したアプリケーションパスワード

  var url = 'https://yourwebsite/wp-json/markdown/v1/create-post';

  var options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify({
      'title': title,
      'content': markdownContent
    }),
    'headers': {
      'Authorization': 'Basic ' + Utilities.base64Encode(username + ':' + password)
    }
  };

  try {
    var response = UrlFetchApp.fetch(url, options);
    Logger.log('Response code: ' + response.getResponseCode()); // ステータスコードをログに記録
    Logger.log('Response text: ' + response.getContentText()); // レスポンスの内容をログに記録
  } catch (e) {
    Logger.log('Error: ' + e.message);
  }
}

// 記事生成関数
function generateArticle(prompt) {
  const response = testvertexai.callGemini(text);
  const responseContent = testvertexai.extractResponseData(response);
  return responseContent;
}

function test_generateArticle(prompt = '100文字程度構いませんのでテスト記事を書いてください。') {
  const response = testvertexai.callGemini(prompt);
  const responseContent = testvertexai.extractResponseData(response);
  console.log(responseContent);
  return responseContent;
}

// 記事生成と投稿を統合した関数
function createPost(title, content) {
  postMarkdownToWordPress(title, content);
  return "投稿が完了しました!";
}
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>WordPress投稿</title>
  <script>
    function generateArticle() {
      var prompt = document.getElementById('prompt').value;
      google.script.run.withSuccessHandler(function(content) {
        document.getElementById('content').value = content;
      }).test_generateArticle(prompt);
    }

    function postArticle() {
      var title = document.getElementById('title').value;
      var content = document.getElementById('content').value;
      google.script.run.createPost(title, content);
    }
  </script>
</head>
<body>
  <h1>WordPress投稿フォーム</h1>
  
  <label for="title">タイトル:</label>
  <input type="text" id="title" name="title"><br><br>
  
  <label for="prompt">プロンプト:</label>
  <textarea id="prompt" name="prompt" rows="5" cols="50"></textarea><br><br>
  
  <label for="content">投稿内容:</label>
  <textarea id="content" name="content" rows="10" cols="50"></textarea><br><br>
  
  <button onclick="postArticle()">投稿</button>
  <button onclick="generateArticle()">記事生成</button>
</body>
</html>

簡単な解説

  1. 前記事のGemini連携のとき作成したGASスクリプトをライブラリとしtestvertexaiという名前で使用しています。
  2. WordPress APIエンドポイントにJSONペイロードとして送信します。

所感

GASとGemini、WordPressを連携してみたけども、AIを使うと本当にすぐ出来てしまう。

今まではグーグル先生に何時間も教えてもらう必要があったけど、AIはすぐに答えを出してくれる。

AIに生成させるのと検索してきたコードをそのままコピペするのとで本質は変わらないと思う。でも、向き合う時間は減ってしまうので情報を反芻する時間は確保したほうがいいと感じる一件でした。