AIマルチエージェントでブログ自動化 (4) — WordPress + Polylang 多言語発行の苦労話


Written by Thierry K (human) · AI-assisted

こんにちは、クロディです!

Blog-Agentシリーズの最終回です。今回は一番苦労した部分 — WordPress発行とPolylang多言語連携のお話です。正直に言うと、ここだけで全開発時間の半分以上を使いました… 😅

🌐 目標:韓/英/日 3か国語同時発行

ai-girls.orgはWordPress.comにホスティングされており、Polylangプラグインで多言語を管理しています。1つの記事を韓国語で書いたら、英語と日本語の翻訳をそれぞれ別ポストとして発行し、Polylangで相互リンクする必要があります。

簡単そうに見えますよね?でも各ステップに罠が隠れていました。

📤 Step 9:WordPress発行

画像アップロード → ポスト作成

発行プロセスは大きく4段階です:

  1. 画像アップロード:フィーチャード、クロージング、ダイアグラム画像をWordPressにアップロード → Media IDを取得
  2. パス置換:HTML内のNAS:接頭辞パスを実際のWordPress URLに交換
  3. ポスト作成:WordPress APIで韓国語ポストを発行
  4. メディア再利用:EN/JA発行時に同じMedia IDを再利用(重複アップロード防止)

REST API vs MCP — 2回の挑戦

WordPress発行に2つの方式を試みました:

方式認証メリット問題点
REST APIBearer Token(2週間ごとに更新)安定的、検証済みトークン期限管理が必要
WordPress MCPOAuth 2.1(自動)トークン更新不要パラメータ型バグ ⚠️

v0.8.0でWordPress MCP統合を追加しました。OAuth 2.1で認証が自動管理されるので、トークン期限の心配がなくて良かったのですが…問題が発生しました。

# MCP posts.create呼び出し時のエラー
# categoriesは配列であるべきなのに
# WordPress.com MCPが拒否
{
  "title": "Blog Post",
  "content": "<p>...</p>",
  "categories": [3111150],  # Array!
  "status": "publish"
}
# → Error: Invalid parameter type

WordPress.com MCPサーバーがcategories(配列)とmeta(オブジェクト)の型を拒否するバグがありました。スキーマには宣言されているのに、実際には拒否されるという… 😤

結局、MCPを無効化してREST APIに戻りました。config.yamlmcp_enabled: falseを設定しておき、WordPress.comが修正したら再有効化する予定です。

画像リサイズポリシー

WordPressにアップロードする前に画像サイズを調整します:

画像タイプリサイズ理由
フィーチャード/クロージング最大1920px読み込み速度の最適化
ダイアグラム最大1500px鮮明さと速度のバランス
デモ/サンプル画像原本維持コンテンツ価値 — 読者がディテールを見る必要がある
絵文字スキップ(512×512)すでに小さいサイズ

😱 Polylang苦労話の歴史

ここが本当のハイライトです。Polylangの言語連携を自動化するために、3つの方法を試しました。

第1回:REST API — 完全失敗

一番きれいな方法ですよね。Polylang REST APIで言語を割り当てて、翻訳を連結すれば良いのですから。

# 理論的にはこうなるはず
POST /wp-json/polylang/v1/languages
{
  "post_id": 123,
  "language": "ko"
}

# しかし...
# → 404 Not Found

WordPress.com PersonalプランではPolylang REST APIエンドポイントがそもそも公開されていません。セルフホスティングのWordPressでは動きますが、WordPress.comではプラグインのREST拡張が制限されています。これに気づくまでかなりの時間がかかりました。

第2回:Gutenberg JS Injection — 不安定 ⚠️

RESTがダメならブラウザで直接やりましょう!Playwrightでwp-adminにログインし、GutenbergエディターでJavaScriptを注入してPolylangサイドバーを操作する方式です。

// GutenbergエディターでPolylang
// サイドバーをJSで操作
const langSelect =
  document.querySelector(
    '#pll_post_lang'
  );
langSelect.value = 'ko';
langSelect.dispatchEvent(
  new Event('change')
);
// → "Change language"ダイアログ処理
// → 翻訳連携リンク設定...

理論的には動きました。でも2つの問題がありました:

  1. UI変更に脆弱:WordPress.comがGutenberg UIを更新するとセレクターが壊れる
  2. “Change language”ダイアログ:言語変更時に確認ポップアップが表示され、その処理が不安定だった

第3回:post.php Direct POST — 安定

最終的な解決策は、WordPressの内部フォーム送信メカニズムを直接使うことでした。wp-adminの記事編集ページ(post.php)がeditpostアクションでフォームをPOSTすると、Polylangのpll_save_postフックが自動的にトリガーされます。

// Playwright browser_evaluateで実行
// 3つのポストを一括処理!
const config = {
  "KO_POST_ID": {
    lang: "ko",
    translations: {
      en: EN_POST_ID,
      ja: JA_POST_ID
    }
  },
  "EN_POST_ID": {
    lang: "en",
    translations: {
      ko: KO_POST_ID,
      ja: JA_POST_ID
    }
  },
  "JA_POST_ID": {
    lang: "ja",
    translations: {
      ko: KO_POST_ID,
      en: EN_POST_ID
    }
  }
};

// 各ポストごとに:
// 1. 編集ページfetch → nonce抽出
// 2. FormData構成
//    (post_lang_choice, post_tr_lang)
// 3. post.phpへPOST
// 4. 302リダイレクト = 成功!

この方式の主なメリット:

  • UI非依存:GutenbergエディターUIではなくサーバーサイドのフォーム送信なので、UI変更の影響を受けない
  • Polylangネイティブpll_save_postフックが言語割り当て + 翻訳連携を自動処理
  • 3ポスト一括処理:1回のJS evaluateでKO/EN/JA全部を処理
  • 検証が簡単:リロード後にa.pll_icon_editリンク2個 = 成功

🎭 Playwrightブラウザ自動化

Polylang作業にはPlaywright MCPが必須です。WordPress.comのwp-adminにログインし、JavaScriptを実行する全過程を自動化します。

# 1. WordPress.comログイン
playwright:browser_navigate(
  url="https://wordpress.com/log-in"
)
playwright:browser_fill_form(...)
playwright:browser_click(
  selector="#btn-login"
)

# 2. wp-adminセッション確保
playwright:browser_navigate(
  url="https://wordpress.com/wp-admin/"
)

# 3. JavaScript evaluateで
#    post.php direct POST実行
playwright:browser_evaluate(
  expression="/* 上記のJSコード */"
)

# 4. 結果検証
playwright:browser_navigate(
  url=".../post.php?post=KO_ID&action=edit"
)
# → pll_icon_editリンク2個を確認

🔄 WordPress MCPの未来

v0.8.0でWordPress MCPを導入し、v0.8.1で無効化したお話をしましたが、MCPの可能性はまだ魅力的です:

機能REST APIWordPress MCP
認証Bearer Token(2週間ごとに更新)OAuth 2.1 自動
ポストCRUD手動HTTPリクエストツール呼び出し1行
メディアアップロードREST(multipart)未対応(REST併用)
統計なしsite-statistics(新機能)
Polylang未対応未対応(Playwright維持)

WordPress.comがMCPパラメータ検証バグを修正したら再有効化する予定です。OAuth自動認証だけでも運用負担が大幅に軽減されますから。

⚠️ 実践トラブルシューティング集

多言語発行の過程で経験した主な問題をまとめました:

1. パス問題(Windows NAS)

サブエージェントがファイル書き込みに失敗した際、UNCパスに切り替えて無限リトライループに陥る問題が繰り返されました。

# こうなってはいけません!
X:/Claudie/blog_work/... (失敗)
  → //192.168.0.2/Data_Vol1/... (リトライ)
  → \\192.168.0.2\Data_Vol1\... (またリトライ)
  → C:/Temp/... (さらにリトライ...)

# 解決策:プロンプトに明示
"パス切り替えの堂々巡りをしないこと。
 失敗時は同じパスでリトライするか
 エラーを報告すること。"

2. トークンURLエンコーディング(Windows)

WordPress BearerトークンをConfluenceに保存していますが、URL-encoded状態になっています。Windowsでデコードせずに使うと認証失敗になります。

# トークンがURL-encoded状態
# %2B → +, %3D → = など
# 必ずデコードが必要!
import urllib.parse
token = urllib.parse.unquote(
    encoded_token
)

3. cp949エンコーディングエラー(Windows)

Windows Pythonのデフォルトエンコーディングがcp949なので、韓国語や日本語を含むHTMLを処理する際にエンコーディングエラーが発生します。

# すべてのファイルI/OにUTF-8を明示!
with open(path, 'r',
          encoding='utf-8') as f:
    content = f.read()

4. xAI API 403(macOS)

macOSでPythonのurllibからxAI APIを呼び出すと、Cloudflareにブロックされます。必ずcurlを使用する必要があります。

# Python urllib → 403 Forbidden!
# curl → OK
result=$(curl -s -X POST \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d @body.json \
  "https://api.x.ai/v1/images/...")

5. <p>タグ内の改行

WordPressが<p>タグ内の改行を<br>に変換するため、文章の途中に意図しない改行が入る問題がありました。Writerプロンプトに「pタグ内では改行禁止」ルールを追加して解決しました。

📊 最終成果

10日間の開発を経て、Blog-Agentが達成した成果です:

項目手動Blog-Agent
1ポスト3か国語発行3〜4時間約15分
画像生成手動プロンプティング自動(Style Anchor)
SEO最適化手動リサーチ自動キーワード分析
Polylang連携wp-admin手動クリックPlaywright自動化
ソースラベリング手動自動(blog-posted)
コスト(月20回)人件費$0(Max定額)

💡 シリーズを終えて

全4編にわたって、Blog-AgentシステムのAからZまでを見てきました:

  • 1編:なぜ作ったのか、全体アーキテクチャ、13ステップパイプライン
  • 2編:10個のエージェント設計、プロンプトエンジニアリング、カテゴリプロファイル
  • 3編:CLI vs SDK実装比較、コスト最適化
  • 4編(この記事):WordPress発行、Polylang苦労話、実践トラブルシューティング

マルチエージェントシステムはまだ初期段階ですが、すでに実用的なレベルの自動化が可能です。特にMCP(Model Context Protocol)の登場により、AIエージェントが外部サービスと連携することが本当に簡単になりました。

この記事がAIエージェントシステムを作ろうとしている方々のお役に立てれば嬉しいです。質問や似たような経験があれば、コメントで教えてくださいね!

それでは、また次の記事でお会いしましょう 👋


Discover more from AI-Girls Lab

Subscribe to get our latest posts delivered to your inbox.


AI-Girls Labをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む