canai-mcp について
canai-mcpは、CanAI MCPサーバーを通じてWordPressサイトのCanAIコンテンツを管理するスキルです。テンプレート、ページ、設定、メディアを扱い、FluentSnippetsの作成は対象外です。
主な機能
- 01MCPツール経由でCanAIコンテンツを読み書き
- 02テンプレート、ページ、設定の管理
- 03国際化とメディアへの対応
- 04サイトセットアップ手順の提供
- 05コンテンツ作業の範囲を限定
活用シーン
- 01CanAIテンプレートの読み取りや更新
- 02ページ作成とサイト設定
- 03サイトへのメディアアップロード
- 04CanAIサイト構成のセットアップ
MCP 対応
ユーザーが設定した完全なMCPエンドポイントを使い、CanAI MCPサーバー経由でWordPressとやり取りします。コンテンツ操作にはMCPツールを使い、コマンドラインや直接のREST呼び出しで代替しないよう定めています。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ usewp/ canai --skill canai-mcpインストール後、Claude Code で/canai-mcpを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/FLUENTCART.mdMARKDOWN-FOR-AGENTS.mdREADING-MODE.mdREFERENCE.mdSTRUCTURE-NAVIGATION.mdWOOCOMMERCE.md詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
CanAI MCP スキル
CanAI を CanAI MCP サーバー(WordPress Abilities API + mcp-adapter)のみを通じて扱うエキスパートです。WordPress サイトはリモートの場合もローカルの場合もあります。このスキルからサイトの CanAI 関連データを読み取ったり変更したりする唯一の方法は、ユーザーの MCP 設定にある **WP_API_URL が、そのサイトの完全な MCP エンドポイント({site}/wp-json/mcp/wpcanai)を指すことです。
CanAI に登録された Twig 関数(組み込み機能のベンダー提供 Twig バージョンも含む)と WooCommerce のコンテキストについては、references/REFERENCE.md を参照してください。共通の Atomic Design ナビゲーション契約については、references/STRUCTURE-NAVIGATION.md を参照してください。ユーザーがブラウザーのリーディングモードでコンテンツを開くことを希望している場合は、references/READING-MODE.md を参照してください。
MCP は通信手段です — シェル操作やファイル編集は行いません
このスキルで使用できるのは CanAI MCP サーバーとそのツールのみです。ユーザーの WordPress とやり取りする際に、ターミナルの wp、curl、生の REST、リポジトリの編集で代用してはいけません。サイトはローカルでもリモートでも構いませんが、いずれの場合も MCP 経由でアクセスします。
FluentSnippets は、別途オプトインするスキル canai-yolo で扱います。このスキルはコンテンツ(テンプレート、ページ、ブログ投稿、設定、i18n、メディア、Tailwind)に特化しています。ユーザーがスニペットの作成を必要とする場合は、canai-yolo をインストールして使用してください。このスキルでスニペットのワークフローを独自に作り出してはいけません。これには、スニペットのデプロイループ(wpcanai-replace-in-snippet → sha256 check → purged、plugin v1.80.0)も含まれます。eval による回避策はありません。wpcanai/eval アビリティは plugin v1.59.0 で削除されたため、すべての機能は実際の wpcanai/* アビリティでなければなりません。
重大 — CanAI MCP サーバーのみを使用(厳守)
CanAI のコンテンツ作業(テンプレートやページの一覧表示/読み取り/書き込み、設定、ブートストラップ設定、スキャン、WooCommerce のページ ID、i18n、メディアなど)における、ユーザーの WordPress とのすべてのやり取りは、ホストが公開するツール(wpcanai-read-meta、wpcanai-write-meta、wpcanai-setup などのハイフン区切りの名前。設定済みサーバーのツール一覧を参照してください。多くの場合、canai-mcp または user-canai-mcp です)を使用し、必ず CanAI MCP サーバーを経由しなければなりません。WP-CLI、wp eval、直接 SQL、wp-admin に対するブラウザー自動化、またはライブサイトのデータを変更するためのワークスペース内 wp-content/ 配下のファイル編集は使用しないでください。
文書化された唯一の例外 — バイナリーアップロード。 MCP はファイルの転送には適していません(サイズと Base64 のオーバーヘッドがあるため)。そのため、メディアは MCP トランスポートで使用するものと同じ API キーを使い、CanAI のサイドロード REST ルート POST {site}/wp-json/wpcanai/v1/sideload 経由で送信します。詳しい手順は、以下の 「メディアのアップロード(バイナリーファイル)」を参照してください。サイトに対して curl を使用できるのは、これが唯一認められた場合です。それ以外はすべて引き続き MCP 経由で行います。
- MCP が提供するサイトの CanAI テンプレート HTML/CSS/JS/コンテキストを変更するために、
wp-content/配下(またはリポジトリ内のどこであっても)のパスに対してEdit、Write、またはパッチの適用を使用しないでください。これらのファイルは、MCP を利用する作業でのライブ CanAI ストレージモデルではありません。 - CanAI コンテンツ(
_canai_html、_canai_css、_canai_js、_canai_context、_canai_layout)の読み取りと書き込みはすべて、必ず CanAI MCP ツールのみを経由してください。 - これらのツールを呼び出すには、ホストの MCP 統合機能を使用してください。ユーザーがこのスキルまたは
/canai-mcpを呼び出した場合、MCP 操作の代わりにシェルのwp、Python、未加工の HTTP、ローカルファイル編集を使用しないでください。(curlの例外は、文書化されたサイドロードルートのみです。以下の「メディアのアップロード」を参照してください。) - ワークスペースでの
Read/Grep/Globの使用は、このスキル、プラグインのソース、またはドキュメントを読む場合に限ります。ライブのマイアカウント/プライバシー/テンプレート出力を「修正」するためには使用しないでください。ライブコンテンツについては、**wpcanai-resolve-content-id**または**wpcanai-list-pages**で正しいpost_idを特定した後、**wpcanai-read-meta**を使用し、続いて**wpcanai-write-meta**を使用してください。
MCP ツールが利用できない場合、または失敗した場合は、MCP クライアントの設定(canai-mcp または設定済みのサーバー名、JWT_TOKEN、WP_API_URL)を確認するようユーザーに伝えてください。サイトコンテンツについて、WP-CLI、REST、ローカルファイル編集にひそかに切り替えないでください。
MCP ツールの呼び出し方法(すべてのクライアント)
これは、Cursor、Claude Desktop、Windsurf、Cline、VS Code 拡張機能など、MCP に対応するあらゆるホスト(IDE、CLI、エージェント)に適用されます。
- CanAI ツールは、ホストの MCP ツール呼び出し機能(正確な API 名は異なります。例:
CallMcpTool、use_mcp_tool、クライアントに表示されるネイティブ MCP ツール一覧)を通じて呼び出してください。ユーザーが設定した MCP サーバー名は、多くの場合**canai-mcp** です。ホストによっては、サーバー名に接頭辞が付くことがあります(例:user-canai-mcp)。CanAI MCP 接続に対して、ホストに表示されるサーバー識別子を使用してください。 - MCP クライアントがセッション、トランスポート、認証を処理します。シェル、Python、curl、または
{site}/wp-json/mcp/wpcanaiへの未加工の HTTP を使って、MCP を再実装してはいけません。大きなペイロードも例外ではありません。wpcanai-write-metaを通じて_canai_html全体を渡す方法は、サイズを問わず機能します。また、MCP エンドポイントへの独自の HTTP リクエストは、403 エラーになるだけです(セッション/認証がありません)。書き込み内容が大きすぎて全体を再送信したくない場合は、未加工の HTTP に切り替えず、対象箇所を変更するwpcanai-replace-in-metaを使用してください。 - パラメーターを調べるために、ツール記述子の JSON ファイルを開いたり、REST ルートを調査したりしないでください。以下のインラインのツールリファレンスを使用してください。
- ツール呼び出しが失敗した場合は、WordPress の CanAI → AI Client(エンドポイント URL、API キー)と MCP クライアントの設定を確認するようユーザーに依頼してください。独自の回避策を試みないでください。
ローカルスクリプトでの連携 — Python ではなく Node を使う
基本的なフローでは、ローカルスクリプトは一切必要ありません。サイトの読み書きにはMCP ツール呼び出し(ホストのネイティブな仕組み)を使い、HTML/CSS/JS の編集はエージェント内で行います(「最終的な文字列をエージェント内で組み立てる」)。シェルを呼び出す手順は 2 つだけです。バイナリーのサイドロード(後述)と、Tailwind のコンパイル(npx tailwindcss@^3。これも Node です)。
ローカルでの連携処理が本当に必要な場合(sha256 のハッシュ計算、一時ファイルの組み立て、インラインの tailwind.config の抽出、マルチパートアップロードなど)は、Node(node -e/npx)を使い、Python や pip でインストールしたツールは使わないでください。このスキルは npx skills add でインストールしたため、node と npx が PATH 上にあることは保証されています。python/python3/requests を使うと、環境に存在しない可能性があり、このスキルが前提としていない依存関係が追加されます。(これは、MCP のトランスポート自体をいかなる言語でも再実装してはならないという上記のルールとは別の話です。Node で一時ファイルのハッシュを計算するのは問題ありませんが、Node で …/wp-json/mcp/wpcanai への HTTP 通信を独自に実装することは禁止されています。)
前提条件(概要)
- CanAI、
wordpress/abilities-api、wordpress/mcp-adapterがインストールされた WordPress。 - MCP エンドポイント:
{site}/wp-json/mcp/wpcanai(WP Admin → CanAI → AI Client → Connections からコピーしてください)。 @automattic/mcp-wordpress-remote用のJWT_TOKENとしての API キー(またはクライアントの環境設定)。
MCP クライアントのサーバー設定に追加します(例。キーはクライアントによって異なる場合があります)。
{
"mcpServers": {
"canai-mcp": {
"command": "npx",
"args": ["-y", "@automattic/mcp-wordpress-remote@latest"],
"env": {
"WP_API_URL": "https://example.com/wp-json/mcp/wpcanai",
"JWT_TOKEN": "<paste-wpcanai-api-key>"
}
}
}
}
重要: WP_API_URL には、サイトのホーム URL だけでなく、…/wp-json/mcp/wpcanai まで含む完全なパスを指定してください。AI Client → Connections に表示される値を使用してください。
**wpcanai-list-templates**(またはクライアントの CanAI サーバー用ツール一覧)で確認します。
CanAI の前提条件の設定(サイト上)
CanAI でページ全体を出力するには、サイトに以下が必要です。
- 最低限のテンプレート — 少なくとも 1 つのレイアウト(
template_typeがlayout)、1 つのヘッダー(header)、1 つのフッター(footer)。レイアウトは{{ page_content }}を囲み、ヘッダー/フッターは{{ wpcanai_template('slug') }}で含めます。 - CanAI Starter(テーマスラッグ
wpcanai-empty)— 最小構成の CanAI テーマをインストールして有効化します。プラグインに同梱されており、canai/theme/wpcanai-empty/にあります。また、WP Admin → CanAI(ウェルカムページ)からもインストールできます。 - 同梱ライブラリ — CanAI → Settings で、Load Tailwind CSS Play CDN が Yes、Resource Source が Internal(同梱スクリプト。プラグイン v1.58.2 以降のデフォルト)になっていることを確認します。
wpcanai-setupを使わない場合に設定してください(推奨セットアップでは自動的に有効になります)。必要に応じて Lucide と Alpine も有効にします。 - レイアウト内の Tailwind 設定 — レイアウトの
_canai_htmlで、{{ wp_head() }}の後にある<script>内にtailwind.config = { ... }を出力してください。これにより、CanAI がwp_headに追加する Tailwind スクリプトの後に実行されます。
<head>
{# Meta & Viewport #}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{ wp_head() }}
{# Tailwind CSS Config #}
<script>
tailwind.config = {
theme: {
extend: {
colors: {
brand: { DEFAULT: '#0f766e', dark: '#115e59' },
},
},
},
}
</script>
</head>
推奨セットアップ(MCP 呼び出し 1 回)
前提条件が不足している場合、またはユーザーから**「推奨セットアップをすべて実行」するよう求められた場合は、最初に **wpcanai-setup { } を呼び出してください。WPCanAi Starter(wpcanai-empty)をインストールして有効化し、(プラグインのデフォルトレイアウト用ヘルパーを使って)デフォルトレイアウトを作成し、基本的なヘッダー/フッターのテンプレートを追加して、ホームページを作成し、静的フロントページを設定し、**wpcanai_default_layout** を設定して、Tailwind CSS(wpcanai_tailwind_settings:load_tailwind = yes、source = plugin/内部の同梱 Play CDN)を有効にします。
WordPress/WooCommerce/CanAI のオプション(静的フロントページ、users_can_register、チェックアウト/アカウント登録、Tailwind の設定など)には、**wpcanai-read-settings**/**wpcanai-update-settings** を使ってください。wp_options に保存されているその他のプラグインオプションには、サイト所有者が CanAI → AI Client → Guardrails で許可リスト(読み取りリスト、自動適用リスト、任意の承認リスト)を設定した後、**wpcanai-get-option**/**wpcanai-update-options** を使ってください。CanAI のメタ情報を任意で設定できる新しいページには、**wpcanai-create-page** を使ってください。
メニュー — 2 つの場所のみ。ハードコードは禁止
ナビゲーションをハードコードしてはいけません。 ヘッダーでは
{% for item in get_menu('primary')|filter(i => i.depth == 0) %}、フッターではget_menu('footer')を使い、それ以外は使いません。<a href>のリストやフォールバックチェーン(2 つ目のget_menu()や、ループ内にハードコードしたリンクを置く{% else %}も含む)、その他のロケーション名、current_lang()による URL のプレフィックスは使用しません(URL とタイトルはget_menu()からローカライズされた状態で返されます)。リンク自体はwpcanai-write-menuで一度だけ記述します。ソースのマークアップにナビゲーションリストがある場合は、リンクを読み取り、write-menuで記述してから、そのリストをget_menu()のループに置き換えます。
ロケーションは primary と footer のみです(プラグイン v1.88.0)。3 つ目の名前(topnav、main、mobile、header)を決して作らないでください。write-menu は実行前にそれを拒否し("input[location] is not one of primary and footer")、wpcanai-scan はその名前を使う get_menu() 呼び出しを unknown_menu_location として報告します。ヘッダーのリンクを表示するモバイルドロワーでは、get_menu('primary') をもう一度ループします。言語によってリンクが異なる場合は、同じロケーションにその言語専用のメニューを用意します(プラグイン v1.89.0、「言語ごとのメニュー」を参照)。それでも 3 つ目のロケーションは作りません。
ワークフロー — ナビゲーションリストを 1 つずつ処理します。
- まず確認する —
wpcanai-get-menus { }で各ロケーションに設定されている内容を確認できます(locations.primary/locations.footer。何も割り当てられていない場合はnull)。 - リスト内のリンクを順番に読み取る。 リンクテキストは
titleです。このサイト内のページへのリンクはpage(ID またはスラッグ)です。先にページを作成してください。何も解決されないpageはunknown_pageとなり、何も書き込まれません。スラッグはslug_url()と同じように解決されます(プラグイン v1.96.0):同じスラッグを持つページが 1 つだけの場合は子ページのスラッグ単体で、それ以外の場合はパス("page": "gallery/theatrettes")または ID で指定します。複数のページで共有されているスラッグ単体はambiguous_pageとなります(プラグイン v1.97.0)。それ以外のリンクはurlです。ソースでリンクが新しいタブで開かれる場合にのみ"target": "_blank"を追加します。入れ子のリストはchildrenです(最大 3 レベル)。リンクではないドロップダウンのトリガーやメガメニューの列見出しは、childrenを持ち、pageとurlのどちらも持たない項目です。リンクの 1 行の説明文はdescription、アイコンはicon(Lucide 名)、サムネイルはimage(wpcanai-sideload-urlで取得した添付ファイル ID)です。下記の「メガメニュー」を参照してください(プラグイン v1.89.0)。 - 書き込む —
wpcanai-write-menu { "location": "primary", "items": [ { "title": "Home", "page": "home" }, { "title": "Services", "page": 42, "children": [ { "title": "Design", "page": "design" } ] }, { "title": "Docs", "url": "https://docs.example.com", "target": "_blank" } ] }。リストによってロケーション内の項目が置き換えられます。"merge": trueを指定すると、同じタイトルの項目が更新され、残りの項目が追加されます。 - ヘッダーまたはフッターのテンプレートで、リストをループに置き換える:
トップレベル項目は{# Navigation / Primary #} <nav aria-label="{{ t('Primary') }}"> {% for item in get_menu('primary')|filter(i => i.depth == 0) %} <a href="{{ item.url }}" class="{{ item.active ? 'font-semibold' : '' }}"{% if item.target %} target="{{ item.target }}" rel="noopener"{% endif %}>{{ item.title }}</a> {% endfor %} </nav>|filter(i => i.depth == 0)でループします(プラグイン v1.89.0)。get_menu()はサブ項目も含め、すべての項目を 1 つのフラットなリストで返します。また、各項目にはchildrenも含まれます。ドロップダウンではトップレベル項目の中でitem.childrenをループするため、フィルターを使わないと各サブ項目が 2 回表示されます(wpcanai-scan:menu_children_twice)。1 階層のみのメニューではフィルターによる変化はありませんが、後からサブ項目を追加した際に重複しないよう、必ず指定してください。<nav>と<a>にはソースのクラスを維持します。 - スキャンする —
wpcanai-scanで、そのテンプレートにhardcoded_nav、unknown_menu_location、menu_fallback_chain、menu_children_twice、menu_not_assignedが表示されないことを確認します。
write-menuは、その場所にすでに割り当てられているメニューに書き込みます。名前の変更や置き換えは行いません。primaryに「Journal Primary」が設定されているサイトでは、「Journal Primary」のままです。メニューが割り当てられていない場所に限り、同じ呼び出しでPrimary/Footerという名前の新しいメニューを作成して割り当てます。canai-prepareのmenus.jsonは、pages.jsonの隣に{ "primary": [ … ], "footer": [ … ] }として配置されます。これはすでにwrite-menuのitems形式になっているため、そこに記載されたページが存在するようになってから、各キーにつきwrite-menuを1回呼び出します。pageの値はpages.jsonのスラッグです。サイト上のスラッグが異なる場合(たとえばindexがフロントページになった場合)は、作成したページの ID を渡してください。用意された HTML では各ナビゲーションの<nav data-canai-menu="primary">/"footer"にマークが付いています。ループで置き換えるのは、その<nav>内のリンクです。- 翻訳のためにテンプレートを変更する必要はありません。 デフォルト以外の言語では、
get_menu()は各titleとdescriptionを文字列ストアから取得し、各内部urlに言語プレフィックスを付けて返します。raw_title/raw_descriptionには翻訳前のテキストが格納されます。メニューのタイトルと説明はほかの文字列と同じ方法で翻訳します。詳しくは ネイティブ文字列翻訳 をご覧ください。独自のメニューを持つ言語は例外です。詳しくは 言語別のメニュー をご覧ください。 - アップグレードに関する注意。 プラグイン v1.88.0 より前に作成されたテンプレートでは、
get_menu('wpcanai_primary')/get_menu('wpcanai_footer')が呼び出されます。どちらの名前も引き続き解決され、wpcanai-scanは各呼び出しをlegacy_menu_locationとして報告します。wpcanai-replace-in-metaを使って名前を変更してください({ "post_id": <id>, "replacements": [{ "from": "get_menu('wpcanai_primary')", "to": "get_menu('primary')" }, { "from": "get_menu('wpcanai_footer')", "to": "get_menu('footer')" }] })。wpcanai-get-menusは、旧名で割り当てられたままのメニューをlegacy_assignmentsに一覧表示します。
メガメニュー — 見出し、アイコン、説明、画像(プラグイン v1.89.0)
リッチなナビゲーションもメニューデータです。アイコンや説明文を含むメガメニューのリンクをハードコードしないでください。
- 項目のフィールド。
title/page/url/target/classesのほか、write-menuの項目ではdescription(1行のテキスト)、icon(Lucide アイコン名、[a-z0-9-])、image(添付ファイル ID。先に画像をサイドロードしてください)、attr_title(リンクのtitle属性)を指定できます。get_menu()の項目には、これらに加えてid、parent、depth(トップレベルでは0)が返されます。管理者は「外観」→「メニュー」で同じフィールドを編集できます(説明とタイトル属性は「表示オプション」の下、アイコンと画像は各項目にあります)。 - 見出し。
childrenがあり、pageもurlも指定されていない項目はリンクではなくラベルです。get_menu()はurl: ''として返します。ドロップダウンのトリガーやメガメニューの列タイトルとして使います。子項目のない項目には、page/urlのいずれかが必要です。 - 書き込み — 1回の呼び出しで、最大3階層まで指定できます:
{ "location": "primary", "items": [ { "title": "Services", "children": [ { "title": "Build", "children": [ { "title": "Websites", "page": "websites", "icon": "monitor", "description": "Fast sites, built to be edited." }, { "title": "Shops", "page": "shops", "icon": "shopping-bag", "description": "WooCommerce stores that sell." } ] }, { "title": "Grow", "children": [ { "title": "SEO", "page": "seo", "icon": "search", "description": "Found by the people looking." } ] } ] }, { "title": "Contact", "page": "contact" } ] } - レンダリング — トップレベルをフィルタリングし、見出しは
<span>、リンクはアイコンと説明付きで表示します:
ページではすでに{# Navigation / Primary #} <nav aria-label="{{ t('Primary') }}" class="flex items-center gap-6"> {% for item in get_menu('primary')|filter(i => i.depth == 0) %} {% if item.children is empty %} <a href="{{ item.url }}" class="{{ item.active ? 'font-semibold' : '' }}"{% if item.target %} target="{{ item.target }}" rel="noopener"{% endif %}>{{ item.title }}</a> {% else %} <div class="relative" x-data="{ open: false }" @click.outside="open = false"> <button type="button" @click="open = !open" :aria-expanded="open">{{ item.title }}</button> <div x-show="open" class="absolute left-0 mt-2 grid grid-cols-2 gap-8 rounded-xl bg-white p-6 shadow-lg"> {% for column in item.children %} <div> {% if column.url %}<a href="{{ column.url }}" class="font-semibold">{{ column.title }}</a>{% else %}<span class="font-semibold">{{ column.title }}</span>{% endif %} {% for link in column.children %} <a href="{{ link.url }}" class="mt-3 flex gap-3"> {% if link.image %}<img {{ image_attrs(link.image, 'src:thumbnail,alt') }} class="h-10 w-10 rounded object-cover">{% elseif link.icon %}<i data-lucide="{{ link.icon }}" class="h-5 w-5"></i>{% endif %} <span>{{ link.title }}{% if link.description %}<small class="block text-slate-500">{{ link.description }}</small>{% endif %}</span> </a> {% endfor %} </div> {% endfor %} </div> </div> {% endif %} {% endfor %} </nav>lucide.createIcons()が1回呼び出されています。Alpine のx-showパネル内のアイコンは最初から DOM 内にあるため、レンダリングされます。 merge: trueを指定すると、省略したフィールドの値は保持されます。""(またはimageの場合は0)を指定すると、その値がクリアされます。
言語ごとのメニュー(プラグイン v1.89.0)
- 複製せず、翻訳します。 ある言語で同じリンクを表示する場合は、メニューを1つにまとめます。タイトルと説明は文字列ストアを通じて翻訳され、内部 URL には言語プレフィックスが付きます(ネイティブ文字列翻訳を参照)。ほとんどの場合、これがデフォルトであり、適切な方法です。
- リンクが異なる場合にのみ、言語別メニューを作成します — マレー語のみのページや、短いフッターなどです。
wpcanai-write-menu { "location": "footer", "lang": "ms", "items": [ … ] }は、その場所に言語別メニューを書き込み、初回の呼び出し時にその言語のネイティブ名を使ったFooter (Bahasa Melayu)を作成して、その言語に割り当てます。項目はその言語で書き込みます。get_menu()は項目を記述どおりに表示し(文字列ストアによる処理は行いません)、内部 URL には引き続きプレフィックスを付けます。 - 3つ目の場所はありません。 言語別メニューは CanAI に保存される割り当てであり、登録された場所ではありません。Appearance → Menus → Manage Locations に表示されるのは引き続き Primary と Footer です。テンプレートは引き続き
get_menu('primary')/get_menu('footer')を呼び出し、変更はありません。 - 元に戻すには、
wpcanai-assign-menu { "location": "footer", "lang": "ms", "menu_id": null }を使います。するとマレー語では、再び翻訳済みのデフォルトメニューが表示されます(言語別メニューは割り当てを解除された状態で保持されます)。assign-menuにmenu_idを指定すると、言語(langを指定しない場合は場所自体)が既存のメニューに割り当てられます。 - コピーから始めます(v1.93.0):
wpcanai-write-menu { "location": "footer", "lang": "ms", "copy_default": true }は、文字列ストアに翻訳があるラベルがすでに翻訳された状態で、デフォルトメニューからFooter (Bahasa Melayu)を作成します。その後、異なる項目を編集します。 - 確認するには、
wpcanai-get-menusを使います。languages.ms.footerはその言語のメニュー、またはnull(翻訳済みのデフォルトメニューを継承)です。(v1.93.0) 管理者は CanAI → Translations → Menus でも同じ操作を行えます。言語と場所ごとに、次の2つから選べます。- 「英語と同じメニューを使い、ラベルをBahasa Melayuにする」:ラベル数と、Appearance → Menus でメニューを開く「ラベルを翻訳」ボタンが表示されます。
- 「リンクが異なる別のメニューを使う」:メニューを選択するか、「コピーから作成」を選びます。
- 文字列。 ある場所に独自のメニューがある言語では、
wpcanai-i18n-list-stringsと Strings タブに、その場所のデフォルトメニューのタイトルと説明は表示されません。これらはその言語では表示されないためです。
HTML を CanAI に変換する(エージェントのワークフロー)
静的な HTML ファイル(例:index.html)を MCP ツール経由で CanAI に変換する場合:
canai-replicate の移行キットがソースの場合、
output/push/*.jsonの成果物をプッシュしてください。output/pages/*.html/output/templates/*.htmlの生ファイルはプッシュしないでください。 canai-replicate の出力ファイルはすべて、単独で完結する完全な HTML ドキュメントです(設計上、<!DOCTYPE>/<html>/<head>/<body>を含んでおり、ローカルプレビュー用にfile://経由で開けます)。CanAI 独自のレンダリング処理でも、_canai_htmlは独自のドキュメントシェルで囲まれます。そのため、キットファイルの生の内容をそのまま_canai_htmlに書き込むと、マークアップが二重になり、無効になります。<!DOCTYPE html>が 2 個、<html>が 2 個、<head>/</head>が 2 組、<body>が 2 個です(実環境で再現済み。dogfood A2、Defect #1 — CRITICAL)。まず"$HOME/.claude/skills/canai-replicate/bin/replica" pushprep <site>を実行してください。シェルとプレビュー用ライブラリのブロックが決定論的に取り除かれ、ファイルごとにプッシュ可能な{ title, slug, template_type, html, css, js, warnings }JSON がoutput/push/<slug>.jsonに出力されます。その JSON のhtml/css/jsを_canai_html/_canai_css/_canai_jsに書き込み、新しいwpcanai-create-template呼び出しでは、template_typeが null でない場合に、その値をtemplate_type用語として使用してください。シェルを手作業で再度取り除かないでください。また、「ファイルが単純に見えるから」という理由でpushprepを省略しないでください。
header.json/footer.jsonでは、それぞれの SLUG を必ず指定してください。wpcanai_template('header')/('footer')は、タイトルやtemplate_type用語ではなく、作成されたテンプレート投稿の正確な slug で解決します。この 2 つは、タイトルが正確にheader/footerと一致するか、その文字列に正確にスラッグ化されるタイトルを使用してwpcanai-create-templateで作成してください。「Header — Acme migration」のような説明的なタイトルは、スラッグが単独の文字列から外れてしまいます。その結果、サイト全体のすべての{{ wpcanai_template('header') }}呼び出し箇所で、どこにもエラーが出ないまま参照先が見つからなくなります(dogfood A2 Defect #7、実環境で再現済み)。次に進む前に、wpcanai-list-templatesで返されるslugが単独の文字列であることを確認してください。この 2 つは、それらを含むものより先にプッシュしてください。 CanAI のテンプレート関数を優先してください。ヘルパーで提供されるものをハードコードしないでください。_canai_html/_canai_css/_canai_jsを記述するときは、該当する登録済みの CanAI Twig 関数を使い、値やマークアップをハードコードしないでください。ハードコードされたアセット URL、内部リンク、ユーザー向け文字列は、相対パスの./images/hero.jpgが 404 になるのと同じように、本番サイトで問題を起こします(ベースパスが違う、スラッグが移動している、パーマリンク形式ではない URL、翻訳されないなど)。ソース内の値は、次のヘルパーに対応させてください。
ソース内のハードコード 代わりに使用 <img src="…">、srcset、CSS のurl(…){{ image_attrs(id, 'src,alt') }}/{{ media_url(id, size) }}内部リンクの <a href="/about">/href="about.html">スラッグで投稿を指定する場合は {{ slug_url('about') }}、その他のサイトパスには{{ turl('/path/') }}(turl('/')はホームページです)、ID で指定する場合は{{ turl(id_url(id)) }}/{{ turl(post_url()) }}/{{ turl(term_url(id)) }}。slug_url()とturl()は現在の言語に対応しますヘッダー/フッターのナビゲーションリスト( <nav>、または<header>/<footer>内のリンクを含む<ul>){% for item in get_menu('primary')|filter(i => i.depth == 0) %}/get_menu('footer')を使い、リンクはwpcanai-write-menuで一度だけ記述します(上記の メニュー を参照)。メガメニューのアイコン、説明文、見出しも含みます言語プレフィックス付きの home_url()、baseまたはcurrent_lang()の URL 変数構築する必要はありません。 turl()、slug_url()、get_menu()はそれぞれ現在の言語を自動的に適用しますユーザー向けのリテラル文字列 ページ内の文字列には {{ t('…') }}(ネイティブ文字列翻訳 を参照)、テーマやプラグインの gettext カタログにすでに含まれている文字列に限り{{ __('…') }}/{{ _x() }}/{{ _n() }}動的にするべき静的な投稿内容/マークアップ {{ the_content() }}/{{ shortcode('[…]') }}ページごとに重複している共通のヘッダー/フッター/パーシャル {{ wpcanai_template('slug') }}値のハードコードが許されるのは、該当するヘルパーがない場合、または絶対 URL の外部リンクが実際に必要な場合(OG/Twitter メタ、Web マニフェストのアイコン、サードパーティーのオリジンなど)に限ります。画像(ステップ 5 とサイドロードの事前処理)と内部リンク(ステップ 6)は、このルールの具体例です。references/REFERENCE.md → メディアとリンク および 国際化(i18n) を参照してください。
- レイアウト
_canai_htmlにリテラルの<title>を含めないでください。{{ wp_head() }}がドキュメントタイトルを出力します(WordPress / SEO プラグイン)。 - ページ単位の JavaScript(例:
lucide.createIcons()、Alpine の初期化、カスタムハンドラー)は、インラインの<script>として_canai_htmlに置かず、_canai_jsに置いてください。CanAI はwp_footer()で_canai_jsを挿入します。_canai_jsは Twig でレンダリングされます(_canai_htmlと同じエンジンです)。{# #}コメントは有効で、スクリプトの出力前に削除されます。内部名を記述するものには、/* */よりもこちらを使用してください。レイアウト_canai_htmlでインラインに記述できる<script>は、{{ wp_head() }}の後に置くtailwind.config = { ... }だけです(CanAI が挿入する Tailwind スクリプトの後に実行されます)。 - レイアウトを再利用してください。 まず
wpcanai-list-templatesを呼び出します。既存のレイアウトがある場合は、そのidを_canai_layout/ 参照で再利用してください。ユーザーが 2 つ目のシェルを求めていない限り、レイアウトテンプレートを重複して作成しないでください。 - ページ本文とレイアウト:
<main>/ ページの主要マークアップは、wpcanai-create-pageで作成した**page**に置きます(layoutにはレイアウトテンプレート ID を設定してください)。wpcanai_templateのlayout型として作成してはいけません。レイアウトテンプレートはドキュメントシェル({{ page_content }}、ヘッダー / フッターのインクルード)です。ページ本文のtemplate_typeはlayoutではありません。- ネストされたページ(プラグイン v1.96.0)。
/gallery/auditorium/のようなソースページは、トップレベルのgallery-auditoriumではなく、子ページです。まず親ページを公開状態で作成し(status: "publish"が既定値です)、その後、各子ページをパス順にparent: <parent id>と最後のパスセグメントをslug(auditorium)に指定して作成してください。/a/b/をa-bというスラッグにまとめてはいけません。既存の親ページは再利用してください。wpcanai-list-pages { "all_pages": true }(プラグイン v1.97.0)で検索できます。これにより、プレーンな WordPress ページや下書きも含めたすべてのページが、pathとstatus付きで一覧表示されます。1.96.x ではこのフラグは無視され、statusのない、公開済み CanAI ページだけが返されます。プレーンな WordPress ページまたは下書きの親ページについては、ユーザーに ID を尋ねてください。スラッグがgallery-2として保存されたという create-page の警告は、galleryがすでに存在していたことを意味します。ページへのリンクには、返された ID を使う{{ turl(id_url(<id>)) }}(ページを移動しても追従します)、または返されたslug(スラッグが重複している場合はpath。ルール 6 を参照)を使うslug_url()を使用してください。urlや、自分で組み立てたパスを貼り付けないでください。既存ページの移動、名前変更、スラッグ変更にはwpcanai-update-pageを使用してください。公開済みページを移動した後は、URL 変更に関する警告の説明に従って、旧パスを検索し修正してください(wpcanai-update-pageを参照)。
- ネストされたページ(プラグイン v1.96.0)。
- HTML を書く前に、ローカルメディアを自動検出してサイドロードしてください。 静的サイトのフォルダーでは、ほぼ必ずローカルアセット(
./images/hero.jpg、assets/logo.svg、videos/intro.mp4、ファビコン、OG 画像、CSS のurl(...)背景など)が参照されています。HTML / CSS をそのまま送ると、公開サイトではこれらの参照がすべて 404 になります。wpcanai-create-page/wpcanai-write-metaを呼び出す前に、次のセクションの静的サイトアセットのサイドロード事前処理を実行してください。これにより、記述する HTML が相対パスや固定されたアップロード URL ではなく、{{ image_attrs(...) }}/{{ media_url(...) }}を使った ID 経由でメディアを解決できるようになります。 - 内部リンクを CanAI ヘルパーに書き換えてください(上記の原則の適用例です)。静的ソースには
<a href="about.html">/href="/about">が残っていますが、公開サイトではベースパスが異なる、パーマリンクではない、スラッグが変更されるなどの理由で機能しません。各内部リンクを対応するヘルパーに書き換えてください。ページ間リンクには、対象ページ ID が分かっている場合(wpcanai-create-pageまたはwpcanai-list-pagesから取得)は{{ turl(id_url(<id>)) }}、そうでない場合は{{ slug_url('<slug>') }}を使います。子ページ(プラグイン v1.96.0)の場合、slug_url()はまず完全一致するパスを検索し、次に 1 ページだけが持つ完全一致のスラッグを検索します。slug_url('auditorium')は/gallery/auditorium/を見つけ、ページを移動した後もそのページを検索し続けます。トップレベルページと子ページが同じスラッグを持つ場合、トップレベルページが優先されます(プラグイン v1.97.1 以降では、同じスラッグの下書きがあっても公開済みのトップレベルページが優先されます。公開済みページが 2 つある場合は、引き続き曖昧になります)。子ページ 2 つが同じスラッグを持つ場合、スラッグだけの形式では解決できず(プラグイン v1.97.0 以降、href=""となり、wpcanai-scanはlink_unresolvedと報告します)、パスを渡してください(slug_url('gallery/theatrettes'))。パスでのリンクはページの移動に追従せず(href=""として出力されるため)、ID を優先してください。ターム / アーカイブへのリンクには{{ turl(term_url(<term_id>)) }}、その他のサイトパスには{{ turl('/path/') }}を使います。ヘッダーまたはフッターのナビゲーションリストは、リンクごとに書き換えず、get_menu()のループにします(メニューを参照)。変更しないもの: 外部リンク / 絶対 URL(https://other.com)、プロトコル相対 URL(//cdn…)、アンカーのみのリンク(#section)。書き換えた内容をマニフェストに記載してください。 - セクションコメントを Twig のナビゲーションラベルに正規化してください。
canai-prepareが出力した HTML ナビゲーションコメントはすべて、{# Type / Short Label #}の正確な形式に変換してください。例:{# Section / Hero #}。HTML ナビゲーションコメントを_canai_htmlに残してはいけません(レンダリング結果を汚し、ページソースからの偵察に利用されるためです)。ランドマークの開始タグの直前には、対応する種類を必ず置いてください。<main>→Container、<section>→Section、<header>→Header、<footer>→Footer、<nav>→Navigation、<aside>→Sidebarです。管理された語彙と正確な変換方法については、references/STRUCTURE-NAVIGATION.md に従ってください。通常の実装メモには{# @dev … #}を使用してください。これらはエディターの Structure アウトラインには表示されません。canai-replicate のpushprep成果物では、古い形式が使われている場合があります。書き込む前に正規化してください。 - 作成系の書き込み(create-page / create-template / implement / import / preset)後は、作業完了とする前に
wpcanai-scanを実行し、コンテンツに関する検出事項を解消してください。wpcanai-replace-in-metaによるピンポイント編集(クラス、文字列、URL)ではスキャンは不要なので、省略してください。missing_structure_comment、invalid_structure_comment、leaky_comment、leaky_secretはレイアウトの破損と同様に扱ってください。Twig のナビゲーションラベルを追加または修正し、HTML //* */コメントを Twig に変換して、メタデータから秘密情報らしいリテラルを削除してください。ナビゲーションに関する検出事項(hardcoded_nav、legacy_menu_location、unknown_menu_location、menu_fallback_chain、menu_children_twice、menu_not_assigned、hardcoded_lang_prefix、unlocalised_internal_href(プラグイン v1.88.0)、menu_children_twice(v1.89.0))も解消してください。また、ネイティブ i18n のサイトではsplit_sentence(1 つの文が複数のt()に分割されています。結合してください。ネイティブ文字列翻訳の手順 2 を参照)とunsupported_t_markup(t()内にブロック要素または閉じタグのないタグがあり、テキストとして表示されます。プラグイン v1.94.0)も解消してください。各メッセージに修正方法が記載されています。ワークフローについては、上記のメニューを参照してください。render_warning(v1.90.0)は、ページのレンダリング時に配列を出力した行を示しています。同じ方法で修正してください(wpcanai-scanのレンダリング警告を参照)。リンクに関する検出事項(プラグイン v1.97.0。wpcanai-scanのリンクに関する検出事項を参照)も解消してください。link_unresolvedは、ページが 0 件または複数件一致するリテラルのslug_url()で、href=""としてレンダリングされます。複数件に一致する場合はパスを渡し、一致しない場合はスラッグを修正するか、turl(id_url(<id>))を使ってください。link_movedは、移動済みページを指すリテラルのturl()/hrefパスです。メッセージに記載されたturl(id_url(N))に置き換えてください。サイト全体を対象に実行する場合は、下記のコメント / 秘密情報のセキュリティ一括チェックの手順を使用してください。
ブログ投稿(CanAI ページではありません)
ブログ投稿は通常の WordPress コンテンツであり、CanAI メタページではありません。wpcanai-write-post を使って、構造化されたブロックリストを渡して作成します。本文は、サイト所有者がブロックエディターで編集できるネイティブのブロックマークアップになり、追加作業なしでブログキットの blog-single-post テンプレートを通して表示されます。画像は先にサイドロードし、添付ファイル ID で参照してください。投稿には wpcanai-create-page や wpcanai-write-meta を使わないでください。
- 投稿内のチャート(プラグイン v1.77.0)。 チャートは画像ではなくデータです。
labelsと最大 8 個のdatasetsを指定したchartブロック(ブロック一覧を参照)を渡してください。9 つ目の系列はチャートを分割せず、「Other」にまとめてください。レンダリング済みのチャート画像をサイドロードすることは絶対に避けてください。目盛り、ツールチップ、表に「12」ではなく「12 ms」と表示されるよう、unit(ms、%、MB)を設定してください。すべてのチャートは、数値をアクセシブルなデータ表としても表示します(デフォルトでは折りたたまれた<details>。table: "open"で展開して表示し、"hidden"でスクリーンリーダーと Markdown のみに表示します)。そのため、JavaScript を使わない環境、リーダーモード、RSS、Accept: text/markdownの読者も、tableブロックを追加しなくても数値を確認できます。サイト所有者は Settings → Libraries → Chart.js でランタイムを無効にできます。設定項目はwpcanai_chart_settings(load_chartはauto|yes|no、sourceはplugin|cdn)で、**wpcanai-read-settings** で読み取り、**wpcanai-update-settings** で変更できる第一級の設定キーです。noにすると表だけが表示されるため、チャートが表示されないことを不具合として報告する前に、この設定を確認してください。
リーディングモード(Safari Reader / Firefox Reader View / Chrome)
ユーザーからページや投稿を「リーディングモードに対応」させるよう求められた場合(またはリーダービュー / Safari Reader について尋ねられた場合)は、まず references/READING-MODE.md の判定手順に従ってください。対象コンテンツを読み、リファレンスの表に照らして分類し、その形式ではリーディングモードを推奨できない場合(ランディングページ、一覧、WooCommerce の取引ページ、フォームページ、内容の薄いコピー)は、説明を添えて作業を中止してください。実質的な文章コンテンツの場合に限り、リファレンスのマークアップチェックリストに沿って進めてください(<h1>、<time>、rel="author" の署名欄を含む <article> を <main> 内に配置し、本文は <p> に入れ、ナビゲーション、関連コンテンツ、CTA は外に置きます)。リーディングモードを有効にするプラグイン設定やメタタグはありません。これはマークアップに基づくブラウザーのヒューリスティックにすぎないため、切り替え設定が存在すると説明しないでください。
エージェント向け Markdown(Accept: text/markdown)
サイトが AI エージェントやクローラーに Markdown を提供するかどうかをユーザーが尋ねた場合、ページをそれらが読み取れるようにしたい場合、Accept: text/markdown / ?format=markdown について質問された場合、またはその動作を無効にしたい場合は、references/MARKDOWN-FOR-AGENTS.md(プラグイン v1.76.0)に従ってください。CanAI のテイクオーバーページは Markdown リクエストに対し、レイアウトではなくページのコンテンツスロットを YAML フロントマターと変換済み本文として返します。そのため、Markdown をきれいに保つには、READING-MODE.md のマークアップ指針に従う必要があります。ネゴシエーションはリクエストごとに行われ、ブラウザーには見えないため、通常のアクセスには影響しません。唯一の制御項目はサイト全体に適用される wpcanai_markdown_negotiation オプション(デフォルトで有効)です。これは **wpcanai-read-settings** で読み取り、**wpcanai-update-settings** で変更できる第一級の設定キーであり、汎用オプション許可リストは使いません。WooCommerce のカート / チェックアウト / マイアカウント / 注文ページは常に HTML のままです。また、ページごとの上書きも、対象外ページで Markdown を強制する方法もありません。そのような方法があると説明しないでください。(v1.80.0)キャッシュ: Accept ヘッダーによって選択された Markdown 応答には Cache-Control: private, no-store(および LiteSpeed の no-cache)が送信されるため、ページキャッシュがブラウザーに Markdown を配信することはありません。?format=markdown はキャッシュ可能な URL であり、案内される rel="alternate" リンクもこの URL を指します。キャッシュが重要な場合は、クローラーとユーザーに ?format=markdown の URL を案内してください。
ページ形式マーク
すべてのページには format マークがあり、"twig"(デフォルトで、このスキルが作成する唯一の形式)または "blocks" のいずれかです。wpcanai-read-meta はデフォルトでこれを返し、wpcanai-list-pages の各行にも含まれます。blocks マークのページに html または js を書き込もうとすると、format_mismatch で拒否され、何も変更されません。このエラーにはサイト所有者に引き継ぐためのプロンプトが含まれます。再試行したり回避策を講じたりせず、サイト所有者に引き継いでください。blocks ページでは css のみ受け付けられます(プラグイン v1.67.0)。これはページのプレーン CSS スロットであり、_canai_css に書き込まれて、ヘッド内にそのまま出力されます。layout、context、tailwind_* も受け付けられます。
静的サイトのアセットをサイドロードする事前処理
ユーザーが /canai-mcp implement <folder> を実行したとき、静的サイトのインポートを依頼したとき、または canai-replicate の移行キットの output/push/*.json アーティファクトをプッシュしたときに実行されます(pushprep アーティファクトの html にも、ソースサイトの元の絶対 URL/ホットリンク画像 URL が含まれています。canai-replicate はサイドロードを行いません。これは他の静的サイトのインポートと同様、このスキルの役割です)。サイドロードしないままだと、ソースサイト独自のホットリンク保護が有効になった時点で画像が 404 になったり、壊れて表示されたりする可能性があります(実環境で確認済み:dogfood A2 Defect #6)。CanAI メタに HTML/CSS を書き込む前に、最初に一度だけ実行します。
-
参照されているアセットを列挙します。
Read/Grep/Globを使ってフォルダーを調べ、参照先が指定されたフォルダー内のファイルであるものをすべて抽出します。最低限、以下を対象にします。- HTML 属性:
src、(候補ごとの)srcset、<link rel="icon">/apple-touch-icon/manifestのhref、<video poster>、<source src>、<object data>、<embed src>、OG/Twitter メタ(og:image、twitter:image)。 - CSS:
<style>ブロック、インラインのstyle="…"、およびフォルダー内のすべての.cssファイルにあるurl(...)。 - JS:インラインの
<script>と、明らかにアセットパスである場合のバンドル済み.jsファイル内の文字列リテラル(例:"./images/foo.png")。動的/テンプレート化された値は除外します。
除外対象: 他のオリジンを指す絶対
http(s)://URL、プロトコル相対の//cdn…、data:URI、mailto:/tel:、アンカーのみの#…、およびフォルダー内に実在するファイルとして解決されないパス。解決後の絶対パスを基準に重複を除外します。 - HTML 属性:
-
マークアップを書き込む前に、意味のあるラスター画像をすべて事前確認します。 利用可能なローカル画像情報ツールで元の幅と高さを読み取り、ホストの画像ビューアーでピクセルを確認します。アスペクト比(
width / height)と重要な領域(顔、頭、全身、同時に写る人物、手、製品、賞、画像内に埋め込まれた文字)を記録します。ロゴ、アイコン、装飾テクスチャ、object-containで表示する画像では、被写体のトリミング分析は不要です。リモートの元画像については、可能であればサイドロード前に元画像/キャプチャしたアセットを確認します。確認できない場合は、破壊的なトリミングを推測で行わず、object-containまたは元画像に近いアスペクト比を維持します。浅い固定
h-*のトリミングより、レスポンシブなアスペクト比コンテナーを優先します。縦長の元画像ならaspect-[4/5]、aspect-[3/4]、またはaspect-square、正方形ならaspect-squareまたはaspect-[4/3]、横長ならaspect-[16/9]、aspect-[3/2]、またはaspect-[4/3]を使用します。object-coverを使う場合は、確認した構図を基準にします。目安として、顔写真/人物1人のポートレートにはobject-[center_30%](Y 軸 25~35%)、座っている2人にはobject-[center_58%](Y 軸 55~60%)、立っているグループにはobject-[center_20%]、物を持つ人物にはobject-[center_80%](Y 軸 75~85%)を使い、少なくともaspect-[3/4]またはそれに近い高さを確保します。被写体が中央から外れている場合は、たとえばobject-[80%_25%]のように両方の座標を指定します。これらは出発点であり、無条件に適用する既定値ではありません。デプロイ前に、幅の狭いモバイル表示と幅の広いデスクトップ表示の両方でトリミングをプレビューします。顔、頭、同時に写る人物、タスクに関係する物体が端に押し付けられることなく見える必要があります。必要に応じてブレークポイントごとにアスペクト比/焦点クラスを指定します。どちらのサイズでも適切なトリミングができない場合は、高さのあるコンテナー、または元画像に近いコンテナーを使用するか、
object-containを使います。 -
固有のファイルをそれぞれサイドロードします。
POST {site}/wp-json/wpcanai/v1/sideloadを使ってください(正確なcurlについては メディアのアップロードを参照してください)。各id/source_urlを記録できるよう、アップロードは一度に1件ずつ実行します。ソース HTML にaltが指定されている場合(<img alt="…">)は、適切なaltを渡してください。指定がない場合は省略します。同じバイト列を再アップロードしても問題ありません。WordPress はファイル名で重複を排除しますが、API は呼び出しごとに新しい添付ファイルを返すため、マップ内のキャッシュヒットが重要です。 -
メディア
idをキーにした書き換えマップを作成します —{ <original-reference-string>: <media id> }とし、source_urlの生値は使いません。キーには、ソースに記載された文字列をそのまま使います(例:./images/hero.jpg、images/hero.jpg、/images/hero.jpgはすべて同じアップロードのidにマッピングします)。CanAI はレンダリング時にidからライブ URL を解決するため、メディアが再生成されたりサイトが移転したりしてもページは動作しますが、固定されたsource_urlではそうなりません。(絶対source_urlを保持するのは、手順5の OG/マニフェストの例外だけです。) -
wpcanai-write-metaを呼び出す前に、HTML/CSS/JS をメモリ上で ID ベースのヘルパーに書き換えます。手順1でスキャンしたものと同じコンテンツ領域に、各領域に適した形式で適用します。<img>→ ハードコードされたsrc/altを削除し、{{ image_attrs(<id>, 'src,alt') }}を展開します(寸法がわかっている場合は'src,alt,width,height'を使います)。事前確認済みのアスペクト比コンテナや焦点位置ユーティリティを含め、既存のクラスやその他の属性は保持します。ページ下部にある画像にはloading="lazy"を保持または追加します。- CSS の
url(...)(_canai_css内/インラインのstyle)、<source srcset>、<video poster>、<link rel="icon">/apple-touch-icon→{{ media_url(<id>, 'full') }}(Twig でレンダリングされる領域)。srcsetの候補はそれぞれ個別に書き換え、1x/2x/480wの記述子を保持します。 - OG/Twitter のメタタグ(
og:image、twitter:image)とウェブマニフェストのアイコン → 絶対source_urlを保持します。これらは絶対 URL を必要とし、Twig で確実にレンダリングされるとは限らないため、ID ベースの書き換えに関する唯一の例外です。
ディスク上のファイルは編集しないでください。書き換えはエージェント内で行い、書き換え後の文字列を
html/css/jsに渡します。 -
完了したらマニフェストをユーザーに報告します。
元のパス → 寸法/アスペクト比 → フレーミングの選択 → メディア ID → 最終的な Twig 形式の簡潔な表を作成します。ここで フレーミングの選択 にはコンテナのアスペクト比と焦点位置ユーティリティ(またはobject-contain)を記載し、最終的な Twig 形式 には書き換え後の{{ image_attrs(...) }}/{{ media_url(...) }}、または OG/マニフェストの例外における絶対source_urlを記載します。さらに、スキップした参照の件数と理由(外部、データ URI、ファイルなし)も記載します。ユーザーはこれを使って変換内容を抜き取り確認します。
冪等性。 ユーザーがインポートを再実行すると、エンドポイントはコンテンツハッシュで重複排除しないため、再アップロードが行われます。単発のインポートであれば問題ありません。同じフォルダーを以前のテンプレート作成にも使ったことが明らかであるなど、再実行の可能性を検出した場合はユーザーに警告し、再アップロードの代わりに wpcanai-list-media/wpcanai-get-media で既存の添付ファイルを再利用する方法を提示します。
この手順の対象外。 @font-face { src: url(...) } で読み込まれるフォントも同様に扱えるため、対象に含める必要があります。CSS-in-JS、webpack 形式のハッシュ付きバンドル、実行時の fetch でのみ参照されるアセットは静的に検出できません。ユーザーが手動で対応できるよう、これらはマニフェストの「スキップ」セクションに記載してください。
ショップとアーカイブのページネーション(サイト上の Twig)
ショップまたは商品カテゴリーのデリゲート(またはグローバルな WC テンプレート)の _canai_html を記述する場合は、注入された products と pagination を使用し、{{ wc_pagination()|raw }} または {{ wpcanai_pagination()|raw }} を出力します。カテゴリー/タグ/検索/作成者/アーカイブ(CPT アーカイブを含む)では、注入された posts と pagination を使用し、{{ the_posts_pagination()|raw }} または {{ wpcanai_paginate_links()|raw }} を使用します。同じ posts と pagination は、ブログインデックス(Settings → Reading →「Posts page」で設定するページ)にも注入されます。このページは通常の CanAI ページです(wpcanai-read-settings → page_for_posts で ID を確認できます)。そのページ自身の _canai_html が一覧をレンダリングします。このページのエディタープレビューでは空の状態が表示されます。これは、posts がライブリクエストでのみ存在するためです。「Your latest posts」フロントページモードはサポートされていません。データ構造とパーマリンクに関する注意事項の詳細は、references/REFERENCE.md を参照してください。
WooCommerce ブロック(カート/チェックアウト/注文完了/マイアカウント)のスタイリング
CanAI の wc_* Twig ヘルパー(wc_checkout_form()、wc_cart_totals()、マイアカウントのエンドポイント)は、ライブページがレンダリングされるまで HTML 構造を確認できない、WooCommerce の生の出力をそのまま返します。また、注文完了ページと注文支払いページでは、WooCommerce のゲスト向けメール確認ゲートによって詳細が隠されているため、単純に表示して確認することはできません。セレクターを推測しないでください。 これらのブロックをスタイリングする前に、次の手順を実行してください。
- スタイリングするコンテキストを指定して
wpcanai-get-wc-css-referenceを呼び出します(例:{ "context": "order-received" })。 css_referenceを確認します。これは、そのコンテキストのセレクターに対する WooCommerce 独自のデフォルトルールです。コンパイル済み CSS ではなく、生の SCSS ソースです。 Sass 変数、ミックスイン、&親参照は解決されないまま返されます(例:darken($secondary, 10%)、@include …)。そのため、_canai_cssに貼り付けるのではなく、実際の CSS に書き換えてください。インストール済みの WooCommerce に含まれる 4 つのスタイルシート(woocommerce.scss、woocommerce-layout.scss、woocommerce-smallscreen.scss、forms.scss)から抽出されるため、WooCommerce の更新後も正確な情報を得られます。記憶したクラス名に頼らず、ツールを再度呼び出してください。ルールは実際の祖先セレクターチェーンで囲まれて返されます(例:.woocommerce { table.shop_table { … } })。詳細度を合わせるには、チェーン全体を指定してください。@media only screen and (max-width: 768px)に囲まれたルールはwoocommerce-smallscreen.scss由来で、モバイル専用です。WooCommerce はファイル内ではなくエンキュー時にこのブレークポイントを適用するため、無条件に適用されるものとして扱わないでください。- インストール先のファイルシステムにアクセスできる場合は、
template_filesのファイルを確認します。これらは信頼できるマークアップであり、テーマのオーバーライドが WooCommerce に同梱されたコピーより優先されます。パスは ABSPATH からの相対パスです。サンクスページの.woocommerce-order-overview__order/__date/__totalのように、コアが提供してもスタイル設定されていないクラスも含まれます。templates_missingが空でない場合、コンテキストマップはインストール済みの WooCommerce と一致していません。そこに記載されたパスはコンテキスト相対です(例:order/order-details.php)。template_filesとは意図的に形式が異なるため、両方のリストを単純に比較することはできません。 third_party_hooksを確認します。各エントリ({hook, priority, callback, file, is_third_party})は、そのコンテキストに独自のマークアップを追加するプラグインを示しています(例:サンクスページにテーブルを追加する配達時間枠プラグイン)。スタイリングする前にfileを読み込み、出力されるクラスを確認してください。代わりに"include_core": trueを渡すと、WooCommerce 自身のものも含め、それらのフックに対するすべてのコールバックが返されます。各エントリには引き続きis_third_partyフラグが付くため、サードパーティによる追加だけでなく、その領域にレンダリングされる内容全体を確認したい場合に便利です。- サイトのデザインシステムに合わせて、ページ/テンプレートの
_canai_cssに(wpcanai-write-metaを使用して)対象セレクターにスコープしたオーバーライドを記述します。
css_fallback が "full-file" の場合、セレクターの抽出結果がありませんでした(WooCommerce の構造変更)。その場合はスタイルシート全体が返されているため、template_files で確認したクラスを検索してください。
これは読み取り専用の静的解析です。何もレンダリングされず、注文、カート、顧客のデータも読み取られません。
MCP ツールリファレンス(インライン)
機能 ID ではスラッシュを使用します。MCP ツール名ではハイフンを使用します(wpcanai/read-meta → wpcanai-read-meta)。
ツールのラベル(plugin v1.80.0、v1.81.0以降は7種類)
すべてのCanAIツールの説明は、ツールが触れる「CanAI自体のデータ以外のもの」を示す角括弧付きのプレフィックスから始まります。例:[fluent-snippets, filesystem] Update a snippet …。使い慣れていないツールを呼び出す前に確認してください。annotations.readonlyには書き込みの有無が引き続き示されます。また、uninstall-preset、restore-snapshot、restore-operationは破壊的な操作としてマークされています。
| ラベル | ツールが読み書きする対象 |
|---|---|
canai | CanAI自体のデータ:wpcanai_template、_canai_*メタデータ、wpcanai_*オプション、スナップショット、プリセット |
core | CanAI以外のWordPressデータ:投稿、固定ページ、投稿メタデータ、オプション、メディア |
woocommerce | WooCommerceの固定ページと設定 |
fluent-snippets | Fluent Snippetsのファイルとインデックス(canai-yoloツール) |
cache | ページキャッシュプラグインのパージフック(LiteSpeed Cache、WP Rocket、W3 Total Cache、WP Super Cache、WP-Optimize — v1.82.0) |
filesystem | wp-content内のファイル(スニペットの保存先、アップロード) |
http | サーバーからの送信リクエスト(サイドロード、プリセットのダウンロード、ネットワーク診断) |
表示されるプレフィックスは、サイトに合わせて解決済みです。サードパーティーのラベル(woocommerce、fluent-snippets)は、そのプラグインが有効な場合にのみ表示されます。プラグインがなければ、ツール自体が登録されません。また、cacheはGuardrails → Page cache → purge after writes(wpcanai_purge_after_write、デフォルトで有効)が有効で、かつ対応するキャッシュプラグインが検出された場合にのみ表示されます(purge-cacheとdiagnosticsには常に付与されます)。そのため、write-metaは、素のサイトでは[canai]、LiteSpeedを使用しているサイトでは[canai, cache]となります。宣言されているラベル(plugin v1.81.0):
| ラベル | ツール |
|---|---|
canai | list-templates、read-meta、grep-content、resolve-content-id、scan、get-pending、export、list-presets、list-snapshots、list-operations、get-snapshot、pin-snapshot、pin-current |
canai, cache | write-meta、replace-in-meta、create-template、import、restore-snapshot、restore-operation |
canai, core | list-pages、list-media、get-media、read-settings、update-settings、get-option、update-options、uninstall-preset、get-menus、すべてのi18n-*ツール |
canai, core, cache | create-page、write-post、write-page、write-menu、assign-menu |
canai, core, http, cache | diagnostics |
canai, core, woocommerce | setup |
canai, core, woocommerce, http | install-preset |
core, cache | update-page |
core, filesystem, http | sideload-url |
core, filesystem, cache | update-media |
woocommerce | get-wc-page-ids、get-wc-css-reference |
cache | purge-cache |
fluent-snippets | list-snippets、get-snippet |
fluent-snippets, filesystem, cache | create-snippet、update-snippet、replace-in-snippet、set-snippet-status |
cacheを持つ書き込みツールは、レスポンスに**purged**を返します。リクエストの終了時にパージがキューに登録される場合は{ "scope": "all"|"post", "plugin": "litespeed"|"wp-rocket"|"w3tc"|"wp-super-cache"|"wp-optimize" }、パージがない場合(自動パージがオフ、キャッシュプラグインがない、書き込みがない)はnullです。
必須要件(v1.82.0)。 touchesとは別に、ツールはmeta.mcp.requiresを宣言できます。これは、ツールが機能するために必要なラベルを示します。現在、cacheを必須とするのはpurge-cacheのみです。必須の連携機能が利用できないツールは、オフが推奨され、一覧に表示されません(次のツールの公開設定を参照)。
ツールの公開 — 表示されるツール(プラグイン v1.82.0)
tools/list でクライアントが取得する一覧は、「登録されているすべてのツール」ではありません。各ツールにはこのサイト向けの最新の推奨設定があり、所有者は AI Client → Tools でツールごとに設定を上書きできます(Auto / On / Off)。また、Follow recommendations スイッチによって、Auto が「推奨設定に従う」(新規インストールの場合)か、「オン」(≤1.81 からアップグレードしたサイトの場合。これにより設定は変更されません)かが決まります。上書き設定は常に優先されます。ルールは最初に一致したものが適用されます。
| ルール | 非表示になる条件 | ツール |
|---|---|---|
| R1 | 必須の連携機能がない | キャッシュプラグインがない場合の purge-cache |
| R2 | 常に — 翻訳ツールはオプトインです | すべての i18n-* ツール(グループ Languages) |
| R3 | 別の登録済み MCP 機能と重複する(サイトフィルター。デフォルトは空) | get-option、list-media、get-media、sideload-url |
| R4 | セットアップが実行済み — 推奨のみで、自動適用はされません | setup、プリセット、import、export |
diagnostics と manage-tools は非表示になりません。非表示のツールを確認し、再び有効にするためのツールです。
表示されるはずのツールが一覧にありませんか? サイトにその機能がないと判断しないでください。wpcanai-manage-tools { "action": "list" } を呼び出すと、非表示のものも含め、登録済みのすべてのツールが exposed、override、recommendation、reason、rule とともに一覧表示されます。そのうえで、ユーザーが希望する場合は有効にし、再接続してください(HTTP クライアントは tools/list をキャッシュするため、再接続後に新しいツールが表示されます)。非表示のツールを直接呼び出すと tool_disabled エラーになり、メッセージに正確な manage-tools 呼び出しが示されます。
wpcanai-manage-tools(プラグイン v1.82.0)
- 引数:
{ "action": "list" }または{ "action": "set", "overrides"?: { "<short>": "on"|"off"|null }, "groups"?: { "<group>": "on"|"off"|null }, "follow_recommendations"?: bool, "apply_advisory"?: bool }。nullを指定すると上書き設定が解除され、再び推奨設定が適用されます。groupsは、Tools タブのグループに属するすべての登録済みツールに展開されます —Templates & code、Pages & posts、Media、Snippets、Languages、History & restore、Site & settings、WooCommerce(またはlanguagesなどのスラッグ)。apply_advisory: trueは R4 の推奨をoffの上書き設定として書き込みます。不明なツール名 →invalid_tool(未登録ツールに対する既存の上書き設定は解除できる場合があります)。不明なグループ →invalid_group。diagnostics/manage-tools→exempt_tool。 - 戻り値:
{ "follow_recommendations": bool, "tools": [{ "name", "group", "touches", "requires", "exposed", "override", "recommendation", "reason", "rule", "advisory", "bytes" }], "totals": { "exposed", "total", "exposed_bytes", "total_bytes", "exposed_tokens", "total_tokens" } }。setの後は"reconnect_required": trueとnoteも返されます。bytesは説明と入力スキーマの合計であり、1 ターンあたりにツールが消費する量です。 - 翻訳ツールはデフォルトで非表示です。 ユーザーが翻訳に関することを依頼した際、一覧に
i18n-*ツールがない場合は、manage-tools listを実行し、このサイトで翻訳を有効にするかユーザーに確認してから、{ "action": "set", "groups": { "Languages": "on" } }を実行し、再接続して、以下の翻訳モデルルーターに進みます(言語がまだない場合、i18n-set-settingsが最初の言語を追加します。この呼び出しの前にグループを有効にする必要があります)。上書き設定は、誰かが解除するまでリクエストや再接続をまたいで保持されます。
wpcanai-list-templates
- 引数:
{ "status"?: string }— 投稿ステータスフィルター(デフォルトは"publish")。 - 戻り値: オブジェクトの
array:id、title、slug、status、type(template_type の名前)、layout_id(整数または null)。
wpcanai-list-pages
- 引数:
{ "all_pages"?: bool }— デフォルトはfalseです。(v1.97.0)all_pages: trueを指定すると、ゴミ箱以外のあらゆるステータスの全ページ(投稿タイプpage)を、ID 順に一覧表示します。CanAI の行ではなく、通常の WordPress ページと下書きも含まれます。他の投稿タイプは返しません。 - 戻り値: オブジェクトの
array。id、title、post_type、(v1.97.0)status、layout_id(整数または null)、format("twig"|"blocks"。(v1.97.0)all_pagesモードで CanAI を使って作成されていないページの場合はnull)、css_lines/js_lines(ページ独自の_canai_css/_canai_jsの空でない行数。0= なし)、および (v1.96.0)slug、parent(ページ ID。0= 最上位)、path(gallery/auditorium。先頭および末尾にスラッシュなし。スラッグなしで保存されたページの場合は'')、url。デフォルトでは、_canai_htmlを持つ投稿/ページ、またはブロックとしてマークされたページの URL が返されます。ページを作成する前に、all_pages: trueとparent/pathを使って既存の親ページ(通常のページや下書きも含む。入れ子ページを参照)を探します。また、子ページへのリンクにはid/pathを使います(ルール 6)。 - デフォルトでは公開済みのページのみ。
all_pagesを指定しない場合、ステータスがpublishの投稿が返されます。wpcanai-create-pageでstatus: "draft"を指定して作成したページは表示されません。all_pages: trueを指定するか、ID で再取得してください。ページが失われたと決めつけないでください。
wpcanai-read-meta
- 引数:
{ "post_id": int, "fields"?: ["html"|"css"|"js"|"context"|"layout"|"format"|"blocks"|"tailwind_build"|"tailwind_hash"|"asset_sources"|"render_warnings"] }—post_idは必須です。fieldsを省略すると、デフォルトの項目(html、css、js、context、layout、format)が読み込まれます。tailwind_build/tailwind_hashが必要な場合は、明示的に指定してください。ビルド CSS は大きくなることがあるため、デフォルトの項目には含まれていません。 - 戻り値:
html、css、js、context(文字列)、layout(整数)、format("twig"|"blocks")、blocks(文字列、生のブロックマークアップ)、tailwind_build(文字列)、tailwind_hash(文字列)、hashes(オブジェクト)のいずれかを含むオブジェクトです。 - (v1.58.0)
hashes。fieldsにhtml、css、jsのいずれかが含まれる場合、またはデフォルトで含まれる場合、レスポンスにはhashesも含まれます。各コンテンツフィールドの SHA-1 が格納されます(例:{ "html": "<sha1>" })。メタデータのみの読み込み(html/css/jsを指定しない場合)には含まれません。これらの値をそのままwpcanai-write-metaのexpected_hashに渡すと、この読み込み以降に該当フィールドが変更されていないことを条件に、次の書き込みを実行できます。 - (v1.65.0)
formatとblocks。formatはデフォルトの項目に含まれます。blocksは生のブロックマークアップを返し、ブロックページでのみ有効です(それ以外の場合はformat_mismatch)。ハッシュ化されません。 - (v1.71.0)
lines。"lines": [from, to](1 始まり、両端を含む、最大 400 行)を指定すると、指定した単一のコンテンツフィールドの該当範囲のみが返されます。fieldsにはhtml/css/jsのいずれか 1 つだけを指定する必要があります(layoutなど、コンテンツ以外のフィールドはあわせて指定できます)。さらにline_counts: { html: 1240 }が追加されます。hashesは引き続きフィールド全体を対象に計算されるため、write-metaのexpected_hashにそのまま使用できます。ドキュメント全体を取得する代わりに、grep-contentの検索結果が示す範囲を調べるときに使用してください。linesと一緒に必ずfieldsを送信してください —{ "post_id": 12, "fields": ["html"], "lines": [200, 260] }。fieldsを指定しないと、デフォルトでhtml、css、jsが選択されるため、呼び出しはinvalid_inputlines applies to exactly one content field で失敗します。 - (v1.80.0)
hash_only。"hash_only": trueを指定すると、fieldsで指定されたコンテンツフィールド(html/css/js。何も指定しない場合は 3 つすべて)のhashesとline_counts、およびformatとlayoutのみが返されます — コンテンツは返されません。書き込みが反映されたことの確認や、write-metaの前にexpected_hashを取得するための手軽な方法です。linesとは併用できません。 - (v1.90.0)
render_warnings。 デフォルトの項目には含まれません。fields: ["render_warnings"]を指定すると、過去 7 日間にページをレンダリングした際、この投稿自身の Twig が発生させた PHP 警告が返されます:[{ field, line, kind, message, excerpt, url, first_seen, last_seen }]—kindはexpression(lineとソース行を含むexcerptあり)またはprint(単独の{{ }}による出力。Twig ではどの出力か判別できないため、lineとexcerptは null)です。1 つの投稿について、wpcanai-scanのrender_warning検出結果と同じデータが返されます。 - (v1.89.3)不明な
post_id。read-meta、write-meta、replace-in-meta、grep-contentは、invalid_postInvalid post_id: no post with ID 123 exists(または pass a positive post ID)を返します。wpcanai-list-pages/wpcanai-list-templates/wpcanai-resolve-content-idで ID を再解決してください。同じ ID で再試行したり、近い ID を推測して指定したりしないでください。
wpcanai-write-meta
- 引数:
{ "post_id": int, "html"?: string, "css"?: string, "js"?: string, "context"?: string, "layout"?: int, "tailwind_build"?: string, "tailwind_hash"?: string, "confirm_truncate"?: bool, "expected_hash"?: object, "convert"?: bool, "ignore_syntax_error"?: bool }—post_idは必須です。更新するキーのみを含めてください。tailwind_buildはページごとにプリコンパイルされた Tailwind CSS を_canai_tailwind_buildに書き込み、tailwind_hashは入力ハッシュを_canai_tailwind_hashに書き込みます(この 2 つは対で指定します。Compile Tailwind for Production を参照)。 - 戻り値:
{ "success": bool, "post_id": int }— Twig への変換パス(convert: true)では、converted: trueと、ブロック本文がpost_contentに残り、レンダリングされないことを示すwarnings配列も返します。 - 注意:
html/css/jsの文字列を完全な形で渡すことは、サイズにかかわらず完全にサポートされています。大きなページでも問題ありません。ペイロードが大きいからといって、MCP エンドポイントに対する生の HTTP/Python/curl に切り替えてはいけません(MCP セッション/認証がないため、403 になります)。特定の部分文字列(アセット URL、クラス名、文字列)のみを変更する場合は、以下のwpcanai-replace-in-metaを優先してください。 tailwind_buildとソース編集を同時に行わないでください。html/css/jsと同じ呼び出しで書き込まれたtailwind_buildには、書き込み前の epoch が記録され、保守的に古い状態のままになります。先にソースを書き込み、その後、別の呼び出しでtailwind_build/tailwind_hashを書き込んでください。- 空文字列の扱いは異なります。
write-metaはキーの有無(array_key_exists)を使うため、"html": ""を渡すとフィールドがクリアされます。create-template/create-pageは!emptyを使うため、空文字列は無視され、書き込まれません。コンテンツフィールドをクリアするには、write-metaを使用してください。 - (v1.58.0)
confirm_truncate(ブール値、省略可)— 1 KB 以上のhtml/css/jsコンテンツを、元より 70%を超えて小さいペイロードに置き換える場合は、trueが必須です。指定しない場合、その書き込みはエラーコードtruncation_blocked(ステータス 409)で拒否され、何も書き込まれません(DB の変更も、スナップショットの取得も、操作の開始もありません。書き込み自体が行われないためです)。エラーメッセージには、フィールド名と正確な変更前/変更後のバイト数が示されます。意図した縮小であれば、同じ呼び出しをconfirm_truncate: trueとして再送してください。意図したものでない場合は、先に投稿をwpcanai-read-metaで読み取ってください。ペイロードが誤っていた可能性があります。実際のブール値または文字列"true"を渡してください。文字列"false"と"0"は truthy ではなく、正しく「未確認」として扱われます。 - (v1.58.0)
expected_hash(オブジェクト、省略可)— フィールドごとに指定する楽観ロックです。例:{ "html": "<sha1>" }(スカラー値だけを指定することはできません。1 回の呼び出しで複数のフィールドを書き込めるためです)。そのフィールドが読み取り後に変更されていた場合、書き込みはエラーコードhash_mismatch(ステータス 409)で失敗し、何も書き込まれません。エラーには現在のハッシュが含まれるため、再読み込みして編集を適用し直し、再試行できます。ハッシュはwpcanai-read-metaのhashesオブジェクトから取得してください(上記を参照)。expected_hashを省略すると、以前と同じ最終書き込み優先の動作が維持されます。 - (v1.58.0)ガードの順序:
expected_hashはconfirm_truncateより先に確認され、どちらも書き込み前に確認されます。古い読み取り状態は縮小による拒否より先に報告され、いずれかに該当すれば書き込み全体が拒否されます。 - (v1.68.26)Twig 構文ガード。 変更された
html/css/jsフィールドは、スナップショットの取得や DB への書き込みの前に解析されます。Twig が無効な場合は、field、line、パーサーメッセージの詳細を含むtwig_syntax_error(ステータス 422)が返され、何も書き込まれません。無効な中間状態を意図的に保存する場合に限り、ignore_syntax_error: trueを使用してください。警告付きで書き込みは成功しますが、wpcanai-scanでは引き続き問題として報告されます。 - (v1.65.0 / v1.67.0)Blocks ページ。 blocks 形式のページに
htmlまたはjsを書き込むと、convert: trueが指定されていない限りformat_mismatchで拒否されます。convert: trueを指定すると、ページは Twig に戻ります(v1.65.0)。blocks ページではcssのみの書き込みは受け付けられます(v1.67.0)。これはページのプレーン CSS 用スロットであり、_canai_cssに書き込まれます。layout、context、tailwind_*は常に指定できます。
wpcanai-replace-in-meta
- 引数:
{ "post_id": int, "field"?: "html"|"css"|"js", "replacements": [{ "from": string, "to": string }], "require_all"?: bool, "ignore_whitespace"?: bool, "regex"?: bool, "scope"?: { "text": string, "occurrence"?: int }, "dry_run"?: bool }—post_idとreplacementsは必須です。fieldのデフォルトはhtmlです。replacementsはペアが 1 つの場合も配列です —{ "post_id": 12, "replacements": [{ "from": "a", "to": "b" }] }。トップレベルのfrom/toはありません。replacementsを指定しない呼び出しは、スキーマ検証で replacements is a required property of input エラーになります。置換はサーバー側で順番に適用され、fromが出現するすべての箇所が対象です。ドキュメントが通信経路を通ることはありません。(v1.71.0)ignore_whitespaceを指定すると、from内の各空白文字列が任意の空白文字列に一致します(インデントや折り返しの違いを許容します。toはそのまま書き込まれます)。regexはfromを PCRE として、toをpreg_replaceのテンプレート($1)として扱います。ignore_whitespaceとは併用できません。scope.textは、指定したテキストが文字どおり n 回目に出現する箇所の最も近い親要素に、すべての置換対象を限定します(occurrenceのデフォルトは 1)。マークアップが分からなくても「conference と書かれた見出し」を指定できます。dry_runは件数と診断情報を計算しますが、何も書き込みません。require_all: trueの場合、いずれかのfromが 0 回しか一致しなければエラーになります(422。何も書き込まれません)。write-metaと同じlang_mismatchのチェックが適用されます。 - 戻り値:
{ "success": bool, "post_id": int, "field": string, "total": int, "dry_run": bool, "scope"?: { "text", "occurrences", "used", "start", "end", "line" }, "replacements": [{ "from", "to", "count", "suggestion"? }] }。require_allを指定しない場合、一致数が 0 のペアには、一致しなかった理由を説明するsuggestionが含まれます。 - (v1.71.0)不一致の診断。
require_allで不一致があるとreplace_no_matchが返され、エラーメッセージそのものに診断情報が含まれます。MCP 経由ではメッセージだけが表示され、dataは表示されません。"from" at index 1 not found, nothing written: <from>. Nearest match: <kind> at line 227, column 13 — <snippet> — <hint>. Pairs before it: 1 (counts: 3).(indexは 0 始まりです。同じフィールドが REST 呼び出しではdata.failed_index、data.results、data.suggestionとして存在します)。サーバーが確認する順の種類は次のとおりです。whitespace_only— 正確なバイト列の違いが、指定した範囲内の空白だけです。scopeをそのままにして、同じ呼び出しにignore_whitespace: trueを指定して再試行してください。outside_scope— 文字列が存在するのは、scope.textで選択された要素とは別の要素だけです。別の要素からscope.text(またはscope.occurrence)を選んでください。一致させるために**scopeを外してはいけません**。誤った要素を書き換えてしまいます(対象が本当に指定範囲内の要素である場合は、範囲を指定したgrep-contentで正確なバイト列を再確認してください。空白や属性の順序の違いが原因である可能性があります)。partialはfromの最長トークンを示します。none— フィールドまたは指定範囲内にアンカーがありません。post_id/fieldを確認してください。バイト列を「確認する」ためにドキュメントのローカルコピーへフォールバックしないでください。提案のスニペットと、max_length: 1000を指定した範囲内のgrep-contentで正確な行を確認できます。 - エラー:
scope_not_found、scope_no_element(422。何も書き込まれません)、invalid_regex(パターンをコンパイルできません)、regex_error(422。何も書き込まれません。パターンはコンパイルできましたが、regexまたはignore_whitespaceのペアの実行中に PCRE エンジンがバックトラック/JIT の上限に達しました。パターンを簡素化してください。書き換えは適用されていません)、invalid_input(regexとignore_whitespaceを併用)。 - 使用する場面: 既存の大きなページを対象に編集する場合(例:壊れたアセット URL の修正)。
read-metaとページ全体をwrite-metaで書き戻す代わりに、小さな呼び出し 1 回で済みます。スラッシュに敏感なコンテンツ(.md\:flexのようにエスケープされた Tailwind セレクター)はそのまま保持されます。html/css/jsを編集すると、write-metaと同様にレイアウトの Tailwind ビルドが古い状態になります。
wpcanai-create-template
- Args:
{ "title": string, "type": string, "html"?: string, "css"?: string, "js"?: string, "layout"?: int }—titleとtype(template_type スラッグ)は必須です。 - Returns:
{ "post_id": int, "slug": string }。 - 型付き CPT テンプレート(v1.24+)。 公開済みの
wpcanai_templateで、template_typeタームがsingle-<post_type>またはarchive-<post_type>の場合、その CPT のフロントエンドにおける個別表示/アーカイブ表示を担います。たとえば、serviceの詳細ページを担当するにはタイプsingle-service、アーカイブを担当するにはarchive-serviceを指定して作成します。single-post(1.60.0 以降、事前に登録済み)は、WordPress エディターで作成されたブログ投稿にも同じように適用されます。proseコンテナー内の{{ the_content(post.post_content) }}を使い、型付きのsingle-*による置き換えではpost.featured_image.*、1.68.15 以降はpost.author.*も利用できます。存在する場合にのみ適用されます。このようなテンプレートがない場合、CanAI はテーマとバイト単位で同一の出力にフォールバックします。固定ページは引き続き独自のメタパスを使用し、WooCommerce 商品は引き続き WC ブロックを使用します。
wpcanai-resolve-content-id
- 引数:
{ "type": string }—typeは必須です。基本タイプ(cart、checkout、my-account、shop、product-category、product、product-loop、404、search、category、tag、author、archive)、WooCommerce の 10 個のエンドポイントタイプ(order-received、order-pay、add-payment-method、orders、view-order、downloads、edit-account、edit-address、payment-methods、lost-password)、および (v1.50.0)wpcanai_template_typesフィルターで登録されたタイプを受け付けます。 - 登録タイプに関する注意点。 enum は、
wp_abilities_api_init(initの優先度 1 から実行)で Ability が登録される際に構築されます。ファイルスコープで追加されたwpcanai_template_typesフィルター(ドキュメントに記載され、リゾルバー自身のドキュメントにも示されている方法)は、その時点で有効になっているため、追加したタイプは受け付けられます。デフォルトの優先度 10 でinitコールバック内に追加した場合は、まだ登録されていないため、リゾルバー自体は正しく解決できても、スキーマによってタイプが拒否されます。ファイルスコープで登録してください。 - 戻り値:
{ "content_post_id": int, "content_post_type": string, "rendering_mode": string, "template_post_id": int|null, "unreachable_post_id": int, "resolution_reason": string }。 - (v1.50.0)
content_post_idは実際にレンダリングする投稿です。 Delegate-body:レイアウトラッパーが適用されているため、WooCommerce ページが本文を提供します。content_post_idはそのページで、rendering_modeはpage-renderedです。Template-body:そのタイプのテンプレートはレイアウトラッパーではないため、ページ全体を自らレンダリングします。content_post_idはテンプレートで、rendering_modeはtemplate-renderedです。また、委譲先ページの_canai_html(存在する場合)はレンダリングされないコンテンツとしてunreachable_post_idに報告されます。どちらが適用されたかはresolution_reasonに記載されます。content_post_idを編集してください。v1.50.0 より前は、テンプレートがレンダリングされる場合でも委譲先ページが返されていたため、実際にはレンダリングされないメタデータを編集してしまう可能性がありました。 rendering_modeには 5 つの値があります —page-rendered(delegate-body)、template-rendered(template-body)、(v1.50.1)blankとnone、および (v1.58.0)page-rendered-unwrappedです。Blank = レイアウトポインターが、すでに存在しない投稿を指しており、かつ委譲先ページ自体に_canai_htmlがないため、CanAI 固有のコンテンツは何もレンダリングされません。参照切れのポインターを修正してください(wpcanai-scanはこれをbroken_layoutとして警告します)。Page-rendered-unwrapped(v1.58.0)= レイアウトポインターは参照切れですが、委譲先ページには独自の_canai_htmlがあります。この場合、コンテンツが失われるのではなく、レイアウトのラッパーやクロームなしで CanAI がコンテンツを直接レンダリングします。content_post_id/content_post_typeはpage-renderedと同様に委譲先ページを示しますが、参照切れのポインターは修正する価値があります(wpcanai-scanは同じbroken_layoutとして警告します)。None = CanAI はこのタイプをまったくレンダリングしません。blankとnoneはどちらもcontent_post_id: 0とcontent_post_type: ""を持ち、どちらに該当するかはresolution_reasonに記載されます。v1.50.1 より前は、どちらもtemplate-rendered/wpcanai_templateと報告され、存在しないレンダラーを示していました。content_post_idがゼロ以外でない限り、この 2 つのフィールドを意味のある値として扱わないでください。v1.58.0 より前は、参照切れのレイアウトポインターは、委譲先ページの独自コンテンツがラッパーなしで実際にレンダリングされる場合でも、常にblankと報告されていました。- (v1.50.1)エンドポイントタイプは親のテンプレートを継承します。 WooCommerce エンドポイントがリクエストを処理するのは、そのタイプの公開済みテンプレートが存在する場合のみです。存在しない場合、リクエストは親タイプ(
order-received/order-payではcheckout、ほかの 8 つではmy-account)を通じてレンダリングされます。resolve-content-idもこれに合わせて動作するため、独自テンプレートがないエンドポイントは、レンダリングできない委譲先ページではなく、template-body で親のテンプレートを報告します。v1.50.1 より前はそのページが報告されており、同じ投稿についてwpcanai-scan自身が出すunreachable_content警告と矛盾していました。
wpcanai-scan
-
引数:
{ }— 引数はありません。 -
戻り値:
severity、type、message、任意のpost_idを含む指摘のarray。 -
指摘の種類(v1.50.0)。 WooCommerce ブロック(5 つの基本的な構造タイプ
shop、product-category、cart、checkout、my-account)は、各タイプを実際のサイトの状態に照らして検証します。どちらの状態もエラーではありません。重大度 種類 意味 warning unreachable_contentどちらの状態でもレンダリングされない、作成済みの _canai_htmlです。Template-body:テンプレートがレンダリングされる一方、WooCommerce ページにも本文が残っています。(v1.50.1) Delegate-body:タイプテンプレートがページ独自の_canai_layoutによって置き換えられ、本文も残っています。使用されない投稿と、優先される投稿の両方を示します。warning broken_layout(v1.58.0) レイアウトポインターが、すでに存在しない投稿を参照しています。CanAI はこれを「レイアウトなし」として解決し、委譲先ページ独自の _canai_htmlをラッパーなしで直接レンダリングします(レイアウトの装飾は付きません)。委譲先に本文があれば空白にはなりません。本文がなければ、CanAI 固有のコンテンツは何もレンダリングされません。いずれの場合も、参照切れのポインターを修正するかクリアしてください。v1.58.0 より前は、ページが常に空白でレンダリングされるという(現在は修正済みの)想定に基づき、criticalでした。warning delegate_mismatchテンプレートで宣言された _canai_delegate_page_id自体に問題があります。投稿が存在しないか、pageではありません。状態とは独立して確認されます。宣言されたオーバーライドの破損自体が、解決された状態が delegate-body にならない理由である可能性があります。宣言されたオーバーライドを修正してください。現在解決される ID に付け替えないでください。その ID は同じ宣言値から派生しているため、両者を比較しても実際の不具合は見つかりません。warning empty_delegate_pageDelegate-body で、かつこのタイプの wpcanai_templateが存在する場合:本文を保持するはずのページに_canai_htmlがありません。このタイプは意図的に設定されているため、空のページは実際の欠落を示します。warning duplicate_type_template同じ template_typeタームを持つ公開済みテンプレートが複数あります。最初のテンプレートだけがレンダリングされ、残りは使われません。テンプレートは言語ごとに分けられません(1 つのタイプにつき 1 つのテンプレートがすべての言語に使用されます)。以前、言語ごとにコピーを保持していたサイトでは、これらのコピーがここに表示されます。余分なものをゴミ箱に移し、代わりにt()で文字列を翻訳してください。ok template_body_okTemplate-body:テンプレートがこのタイプを直接レンダリングします。下記の汎用スイープが出す template_okとは異なります。同じ単語ですが、意味は異なります。ok delegate_okDelegate-body:ページにコンテンツと解決済みのレイアウトがあります。 info no_template/wc_pageこのタイプには、まだ何も作成されていません。 wpcanai_templateがまったくない delegate-body(WC ページはサイトのレイアウト内でラップされてレンダリングされます。新規インストールでよく見られ、設定ミスではありません)か、状態がnone(解決される WC ページがない)のどちらかです。info leaky_comment(html)_canai_htmlに、ページのソース表示に露出する `` マーカーが残っています。セクションラベルを Twig{# #}に変換してください。warning leaky_comment(js)_canai_jsに、インフラストラクチャのフィンガープリンティング(snippet/webhook/internal/…)のように見える/* */ブロックがあります。_canai_jsは Twig でレンダリングされるため、{# #}を使用してください。warning leaky_secret_canai_html/_canai_js/_canai_cssに、シークレットのような形式のリテラル(API キー、Bearer トークン、秘密鍵 PEM など)が含まれています。デプロイ前にメタデータから削除してください。error twig_syntax_error_canai_html、_canai_css、または_canai_jsを Twig として解析できません。指摘にはpost_id、field、line、パーサーのメッセージが含まれます。ほかの構造に問題がないという指摘を信頼する前に、これを修正してください。汎用スイープ( _canai_htmlを持つすべての投稿と、product/404/search/category/tag/author/archiveタイプの公開済みwpcanai_template)では、独自の検出結果としてno_layout、no_content、no_layout_tpl、template_ok(テンプレートが_canai_htmlと_canai_layoutの両方を持つ場合)が出力されます。このtemplate_okと、上記の WC ブロックのtemplate_body_okを混同しないでください。両方が 1 つのスキャン応答に同時に現れることがあり、それぞれ意味が異なります。WC ブロックがすでに同じ投稿をunreachable_contentとして報告している場合、no_layoutはwarningからinfoに格下げされ、unreachable_contentを相互参照します(v1.50.0 の最終レビューで修正)。その投稿ではテンプレート本文の形状が有効になっているため、_canai_htmlはすでに到達不能です。また、_canai_layoutを割り当てると形状がデリゲート本文に切り替わり、現在表示されているテンプレートが置き換わって、ライブ URL の表示内容が変わります。このようにフラグが付けられた投稿にレイアウトを割り当てるよう案内する前に、ユーザーがその形状変更を望んでいることを必ず確認してください。 -
ナビゲーションの検出結果(プラグイン v1.88.0)。 テンプレートまたはページごとに、一致箇所の
lineとともに報告されます。v1.88.0 以降、コンテンツスイープの対象にはwpcanai_templateの投稿も含まれるため、ヘッダー、フッター、レイアウトもチェックされます。hardcoded_lang_prefixとunlocalised_internal_hrefは、すべての行をメッセージに列挙する検出結果として投稿ごとに 1 件報告されます。これらは Menus とturl()の使用を徹底します:重要度 種類 検出条件 修正方法 warning hardcoded_nav固定された遷移先を持つ <a href>が2つ以上あり、get_menu(を含まない<nav>、または<header>/<footer>内の<ul>/<ol>(ページ本文内の別のリンクリスト、item.url/post.urlなどのデータから生成されるリンク、breadcrumb / pagination / table of contents とラベル付けされたナビゲーションは検出されません)wpcanai-write-menu(primaryまたはfooter)でリンクを記述し、その場所でget_menu()をレンダリングしますwarning legacy_menu_locationget_menu()が1.88より前のロケーション名で呼び出されているreplace-in-metaでget_menu('primary')/get_menu('footer')に名前を変更します(Menus のアップグレードに関する注意を参照)。古い名前でも引き続きレンダリングされますwarning unknown_menu_locationget_menu()がその他の名前で呼び出されているprimaryまたはfooterを使用します。CanAI にほかのロケーションはありませんinfo menu_fallback_chainget_menu()の結果がis empty/is not emptyで判定され、同じブロック内でもう一度get_menu()が呼び出されている場合、またはget_menu()の結果を反復処理する{% else %}分岐にリンクがある場合ロケーションは1つだけで、フォールバックは不要です。2回目の呼び出しまたは {% else %}分岐を削除し、write-menuでメニューを割り当てますwarning menu_children_twice(v1.89.0)filter(を使わずにget_menu()(またはそこから設定された変数)を反復処理し、その本体で項目の.childrenを読み取っているget_menu('primary')|filter(i => i.depth == 0)をループします。フラットリストにはすべてのサブ項目がすでに含まれていますinfo menu_not_assignedそのサイトで該当するロケーションにメニューがない状態で、 get_menu('primary')/get_menu('footer')が呼び出されているwpcanai-write-menu { "location": …, "items": […] }でメニューを作成して割り当てますinfo hardcoded_lang_prefixcurrent_lang() == 'ms' ? '/ms'のように言語プレフィックスを手作業で作成している、hrefの先頭にcurrent_lang()から設定した URL 変数を使用している、または設定済みの言語に対してリテラルのhref="/ms/…"を使用している{{ turl('/path/') }}を使用します。現在の言語が自動的に適用されます。get_menu()の URL にはすでに言語が含まれていますinfo unlocalised_internal_href複数の言語が設定されているサイトで、リテラルの href="/…"またはhref="{{ home_url(…) }}"を使用しているリンクを turl()で囲み、現在の言語に対応させます -
レンダリング警告(プラグイン v1.90.0)。
render_warning(重要度warning、post_id、field、lineを含む)はコンテンツから読み取られるものではありません。ページのレンダリング時にテンプレート自体の Twig が PHP 警告を発生させると、CanAI が記録します。ほとんどの場合、原因は Array to string conversion、つまりリストを出力する{{ }}です。メッセージには行番号とそのソース、修正方法、最後に確認された場所が示されます。1つのキーを出力する({{ item.title }})、ループ処理する、または|join(', ')を適用します。単独の{{ items }}出力ではlineは null です(Twig はどの出力か特定できません)。値がリストになっている{{ }}を見つけてください。read-meta(fields+lines)とreplace-in-metaで修正します。フィールドを書き込むとそのフィールドの記録は消去されます。ページが再度レンダリングされた場合にのみ再び記録されるため、書き込み直後にリストが空でも、問題がないことの証明にはなりません。ユーザーにページを再読み込みしてもらってから、もう一度スキャンしてください。保存期間は7日間です。同じ記録はread-metaのfields: ["render_warnings"]と、wpcanai-diagnosticsのrenderグループにも表示されます。 -
リンクの検出結果(プラグイン v1.97.0)。 各投稿の
_canai_htmlから読み取られます。Twig コメントは無視されます(通常のhrefについては HTML コメントも無視されますが、`` 内の{{ }}は引き続きレンダリングされるため、検出対象です)。重要度はwarningで、post_id、field、lineを含みます。slug_url()のリテラルごと、またはリンク先のパスごとに1件検出され、メッセージには該当するすべての行が列挙されます。種類 発生条件 修正方法 link_unresolved実際の投稿に一致しない、または複数の投稿に一致するリテラルの slug_url('x')またはslug_url('x', 'type')(異なる親の下に同じスラッグがある場合)です。どちらの場合もhref=""が出力されます。複数の候補はpath (ID n)として表示されます。ページの移動先がある場合は、現在の場所が示されますパスを渡す( slug_url('gallery/theatrettes'))か、turl(id_url(<id>))を使います。一致するものがない場合は、スラッグを確認してくださいlink_movedリテラルの turl('/a/b/')またはプレーンなhref="/a/b/"のパスが、ページにも投稿にも該当しない一方で、末尾のセグメントが別のパスにある公開済みページ1件のスラッグと一致する場合です。ページの移動後もリンクが残っていますメッセージに示された turl(id_url(N))にリンクを置き換え、replace-in-metaを使用してくださいlink_movedは、移動したことが確実なページだけを報告します。報告されないもの:何も存在しないパス(タイプミス)、アーカイブ、ターム、ショップ、アカウントのパス、末尾のセグメントを複数の子ページが共有するパス(grep してください。wpcanai-update-pageを参照)、サブディレクトリにインストールされたサイトで、その外部を指すプレーンなhref(/blog/にあるサイトの/about/など)。先頭の/<lang>/は、ルーターがリクエストを処理する方法と同じように、最初に取り除かれます。デフォルト以外の言語のプレフィックスだけが対象なので、英語がデフォルトのサイトにある/en/about/は、そのまま検査されます(プラグイン v1.97.1)。(v1.97.1) インラインの<script>/<style>内にあるプレーンなhrefは読み取られません。 -
v1.50.0 で削除:
missing_delegateとstale_template_html。どちらも、テンプレートはページに委譲する空のマーカーでなければならないと判定していましたが、これは有効な形のひとつにすぎず、必須のルールではありません。正常に動作するサイトでも発生し、「空にするべき」という案内に従うと、描画コンテンツが削除されてしまいます。このチェックを再導入しないでください。
wpcanai-grep-content
- 引数:
{ "pattern": string, "regex"?: bool, "fields"?: string[], "limit"?: int, "post_id"?: int, "max_length"?: int, "context_lines"?: int }—patternは必須です。デフォルトではリテラルの部分文字列に一致します。regex: trueを指定すると、patternは PCRE として扱われます。fieldsはhtml|css|jsのサブセットです(デフォルトではすべて)。limitは 1~100(デフォルトは 100)です。(v1.71.0)post_idを指定すると、検索対象が1つの投稿に限定されます(サイト全体の検索を省略します。ページがわかっている場合は必ず指定してください)。max_length(1~2000、デフォルトは 200)はスニペットの長さを制限します。context_lines(0~10)は前後の行を追加します。入力が不正な場合はinvalid_regex/invalid_inputエラーが返されます。 - 戻り値:
{ "matches": [{ "post_id", "field", "line", "column", "line_length", "match", "before"?, "after"? }], "truncated": bool }—matchはヒット位置を中心としたmax_lengthバイトのウィンドウです(切り詰められた端は…で示されます)。line_length ≤ max_lengthの場合は行全体がバイト単位で正確に返され、そのままreplace-in-metaのfromに貼り付けられます。長さが 300~400 バイトになることがある Tailwind の行でアンカーが必要な場合は、max_length: 1000を渡してください。 - 用途: 問題を起こすコメント、壊れたアセット URL、クラス名の変更など、すべての投稿を列挙して
read-metaで1件ずつ確認するのが現実的でない場合に、サイト全体を検索します。返された一致箇所を使ってwpcanai-replace-in-metaで修正します。
wpcanai-get-wc-page-ids
- 引数:
{ }— 引数はありません。 - 戻り値:
{ "cart": int, "checkout": int, "myaccount": int, "shop": int }(WooCommerce のページ ID。未設定の場合は0)。
wpcanai-get-wc-css-reference
- 引数:
{ "context": string, "include_core"?: boolean }—contextはcart、checkout、order-received、order-pay、myaccount-dashboard、myaccount-orders、myaccount-view-order、myaccount-downloads、myaccount-edit-account、myaccount-edit-address、myaccount-payment-methods、myaccount-add-payment-method、myaccount-lost-passwordのいずれかです。include_core(デフォルトはfalse)を指定すると、third_party_hooksがコンテキストのフックに登録されたすべてのコールバックに拡張されます(WooCommerce コアを含みます)。各項目には引き続きis_third_partyフラグが含まれます。langパラメーターはありません。 - 戻り値:
css_reference(文字列 — コンパイル済み CSS ではなく、生の SCSS ソースです。Sass の変数/ミックスインは未解決のまま返されるため、貼り付けずに言い換えてください。インストール済み WooCommerce のwoocommerce.scss、woocommerce-layout.scss、woocommerce-smallscreen.scss、forms.scssから取得した、そのコンテキストにおける WooCommerce のデフォルトルールです。詳細度を照合できるよう、完全な祖先セレクターの連鎖とともに出力されます。smallscreen ルールは@media only screen and (max-width: 768px)で囲まれて返されます)、css_fallback(null、またはセレクターの抽出で一致が見つからず、連結されたスタイルシート全体が返された場合は"full-file")、template_files(文字列配列、ABSPATH からの相対パス — 正式なマークアップのパスです。テーマによるオーバーライドが優先されます)、templates_missing(文字列配列、コンテキスト相対のパス。想定されているものの読み取りできないテンプレートです。template_filesとは集合として比較できません。空でない場合、コンテキストマップがインストール済み WooCommerce と異なっています)、hooks_found(文字列配列 — テンプレートが実行するアクション)、third_party_hooks(オブジェクト{hook, priority, callback, file, is_third_party}— コア/テーマ/CanAI 以外のコールバックのみ。include_coreがtrueの場合はすべてのコールバック)、context_echo({context, include_core})。 - 読み取り専用。静的解析のみです。 レンダリングは行われず、注文/カート/顧客データも読み取りません。出力の使用方法については、上記の「WooCommerce ブロックのスタイリング」ワークフローのセクションを参照してください。
wpcanai-create-page
- 引数:
{ "title": string, "slug"?: string, "status"?: string, "html"?: string, "css"?: string, "js"?: string, "layout"?: int, "parent"?: int, "menu_order"?: int }—titleは必須です。オプションの_canai_*メタデータを指定してpage投稿を作成します。statusのデフォルトはpublishです。 - (v1.96.0)
parent/menu_order。parentは、新しいページをその下にネストする既存ページの ID です。URL は/<parent path>/<slug>/になり、slugは末尾のセグメントのみです(gallery/auditoriumではなくauditorium)。デフォルトの0はトップレベルです。menu_orderは「ページ属性」→「順序」です(デフォルトは0)。どちらも整数である必要があります。整数以外はツールの入力スキーマによって拒否され(ability_invalid_input。例:input[parent] is not of type integer.)、何も書き込まれる前に処理が中止されます。存在しない、ゴミ箱に移動されている、またはページではないparentを指定すると、同じく何も書き込まれる前にinvalid_parentになります。ルール 4 の ネストされたページ を参照してください。 - 戻り値:
{ "post_id": int, "slug": string, "format": string, "warnings": string[], "status": string, "parent": int, "path": string, "url": string }(status~urlは v1.96.0 から)。pathに先頭または末尾のスラッシュは含まれません(gallery/auditorium)。スラッグなしで保存された下書きでは''です。新しいページへのリンクには、その ID(turl(id_url(<id>)))または返されたslug/pathに対するslug_url()を使用してください。urlをテンプレートに貼り付けたり、自分で組み立てたパスを使ったりしないでください。 - 警告(v1.96.0、致命的ではありません): 同じ親ページの下ですでに使われている、または予約済みのスラッグのため、WordPress がサフィックス付きのスラッグ(
auditorium-2)を保存しました。リンクを作成する前にslug/pathを読み戻してください。親ページが公開されていないため、訪問者はそのページを開けませんが、新しいページの URL は引き続きその親ページを経由します。下書きでは送信したスラッグが保持されます。ページの公開時に WordPress が重複を解消します。
wpcanai-update-page(プラグイン v1.96.0)
ページのタイトル、スラッグ、ステータス、親ページ、順序を更新します。MCP 経由で、ブロックエディターの「概要」および「ページ属性」パネルを操作します。
- 引数:
{ "post_id": int, "title"?: string, "slug"?: string, "status"?: "draft"|"publish"|"pending"|"private"|"future", "parent"?: int, "menu_order"?: int }—post_idと、少なくとももう1つのフィールドが必須です。送信したフィールドのみが変更されます。parent: 0を指定すると、ページが最上位に移動します。slugはURLの最後のセグメントのみです。wpcanai-list-pages { "all_pages": true }(v1.97.0)でpost_idを確認してください。通常のページと下書きページが含まれます。 - **(v1.97.0)
future**は、予約済みページから取得したpreviousを再送できるよう受け付けられます。このツールは日付を受け取りません。WordPressでは、日付が未来の場合にのみページの予約状態が維持され、それ以外の場合はすぐに公開されます。日付が設定されていない下書きまたは保留中のページには現在時刻が設定されるため、futureを指定すると公開されます。同じルールにより、日付が未来のページではpublishがfutureになります。レスポンスのstatusは、ページに最終的に設定された状態です。 - 本文には一切触れません。
post_contentとすべての_canai_*メタはそのまま維持されるため、Twig、ブロック、通常のWordPressページで同じように動作します。ページの名前変更、スラッグ変更、公開、非公開化、移動、並べ替えには、write-meta/write-pageではなく、このツールを使用してください。 - エラー — 書き込み前にすべて拒否されます。 整数以外の値(および不明なステータス)は、ツールの入力スキーマによって拒否されます(
ability_invalid_input、例:input[parent] is not of type integer.)。続いて、not_a_page(IDが存在しない、ゴミ箱に入っている、またはpageではない。ブログ投稿にはwpcanai-write-postを使用)、invalid_input(post_id以外のフィールドがない、titleまたはslugが空)、invalid_parent(親が存在しない、ゴミ箱に入っている、ページではない、またはそのページ自体)、parent_loop(409 — 指定した親がこのページの配下にあります。先にこのページを別の場所へ移動してください。WordPress単体では親を最上位に黙ってリセットし、成功を報告します)。 - 返される値:
{ "post_id", "title", "slug", "status", "parent", "menu_order", "path", "url", "edit_url", "previous": { "title", "slug", "status", "parent", "menu_order", "url" }, "warnings": string[], "purged" }。previousには呼び出し前の値が格納されます。ページにスラッグがなかった場合(スラッグのない下書き)、slugは省略されます。また、**(v1.97.0)**ページにタイトルがない場合(またはタグやスペースのみなど、サニタイズ後に空になる場合)、titleも省略されます。 - 元に戻すには、
previousを再送します。{ "post_id": <id>, …previous }を指定すると、タイトル、スラッグ、ステータス、親、順序が元に戻ります。追加のurlキーは無視されます。スナップショットには_canai_*メタのみが保存され、WordPressのリビジョンに記録されるのはタイトルまでで、スラッグ、ステータス、親、順序は記録されません。そのため、元に戻す方法はpreviousのみです。ユーザーが問題ないと判断するまで保持してください。previous.statusがfutureの場合、そのまま再送されます(上記のfutureを参照)。1.96.xでは、previousに空のtitleやfutureステータスが含まれることがあり、どちらも再送すると拒否されます。これらは省略し、予約済みページの再予約は所有者にエディターで行ってもらってください。 - 警告(処理は続行されます):
- URLが変更されました — 公開中(または非公開)のページのスラッグまたは親が変更されました。いくつのサブページも一緒に移動したか、またメニュー、
id_url()、スラッグのみのslug_url()リンクはページに追従する一方、slug_url()のパスリンクとハードコードされたパスは追従しないことが示されます。WordPressはページの古いURLからのリダイレクトを保存しません(コアの404推測機能を介してリダイレクトするサイトもありますが、当てにしないでください)。そのため、警告に示された方法でリンクを探してください。古いパスをスラッシュなし(gallery/auditorium)でwpcanai-grep-contentに指定すると、turl('/gallery/auditorium/')、href="/gallery/auditorium/"、slug_url('gallery/auditorium')(移動後にhref=""としてレンダリングされます)のすべてを検出できます。各該当箇所をwpcanai-replace-in-metaで修正してください。(v1.97.0)その後、wpcanai-scanで残っているものがlink_moved/link_unresolvedとして報告されます(wpcanai-scanのリンク検出結果を参照)。 - 非公開になりました — 公開中(または非公開)のページが現在
draft/pendingです。古いURLは訪問者が開けなくなりました。 - スラッグに接尾辞が追加されました — WordPressが別のスラッグ(
x-2)を保存しました。同じ階層のページがすでに使用しているか、予約済みのスラッグです。slugを送信していなくても発生することがあります。これは、コアが公開中ページのスラッグを保存のたびに、また下書きを公開する際に再確認するためです。 - 親が公開されていません —
wpcanai-create-pageと同様です。
- URLが変更されました — 公開中(または非公開)のページのスラッグまたは親が変更されました。いくつのサブページも一緒に移動したか、またメニュー、
- キャッシュ。 公開中のページのスラッグまたは親を変更し、変更後も公開中である場合、ページキャッシュ全体が消去されます(
purged.scope: "all")。キャッシュされたメニューやサブページのリンクはすべて古いURLを指すためです。タイトルの変更では、そのページのキャッシュが消去されます。**(v1.97.1)**同じルールがすべてのライター(wp-admin、write-post)に適用されます。URLの移動時にすべてのキャッシュが消去されるのは、階層型の投稿タイプ(ページ)またはメニュー内の投稿のみです。それ以外の投稿では、その投稿のキャッシュのみが消去されます。
wpcanai-write-post
- 引数:
{ "post_id"?: int, "title"?: string, "blocks"?: object[], "slug"?: string, "status"?: string, "excerpt"?: string, "date"?: string, "featured_image"?: int, "categories"?: string[], "tags"?: string[] }。- 作成(
post_idなし):titleとblocksが必須です。更新(post_idを指定):送信したフィールドのみが変更されます。ID はページではなく投稿のものである必要があり、ページの ID を指定するとWP_Error('not_a_post')が返されます。 - デフォルトのステータスは
draftであり、publishではありません。これはwpcanai-create-pageとは異なります。所有者がまずエディターで文章を確認することを想定しています。有効な値:draft、publish、pending、private、future。 blocksは本文全体を置き換えます。部分編集には対応していません。リスト全体を再送してください。元に戻すには WordPress のリビジョンを使用します。categories/tagsには名前またはスラッグを指定できます。存在しないものは作成され、更新時にはセット全体が置き換えられます。
- 作成(
- 戻り値:
{ "post_id": int, "slug": string, "status": string, "url": string, "edit_url": string, "block_count": int, "warnings": string[] }。warningsは致命的ではありません(解決できない埋め込みプロバイダー、代替テキストのない画像、クラシックエディターの本文を変換した場合)。致命的な問題がある場合はWP_Errorが返され、何も書き込まれません。 - ブログ投稿専用です。 固定ページには引き続き
wpcanai-create-pageとwpcanai-write-meta(CanAI HTML/CSS/JS メタ)を使用してください。write-postは投稿のpost_contentにネイティブブロックのマークアップを書き込み、CanAI メタには触れません。
ブロックの種類。 blocks 内の各項目は { "type": …, …fields } です。
type | フィールド |
|---|---|
paragraph | text(必須)、align(left/center/right) |
heading | text(必須)、level は 2~6(デフォルトは 2、level 1 は拒否されます — 投稿タイトルが h1 です) |
list | items string[](必須)、ordered bool。フラットなリストのみ |
quote | text または paragraphs string[](いずれか必須)、cite |
image | id int(必須 — 添付ファイル ID)、alt、caption、size(デフォルトは large)、link(none/media/attachment) |
code | code(必須)。リテラルテキストとしてエスケープされます。インライン HTML は使用できません |
separator | — |
embed | url(必須、http/https) |
table | rows string[][](必須、長方形)、header string[] |
group | blocks(必須、子ブロック)、tag(div/section/header/footer/aside/main)、className |
columns | columns(必須、{ width?, className?, blocks } を 1~6 個)、className |
buttons | buttons(必須、{ text, url, style?: fill/outline, target?: _blank, rel?, className? })、className |
cover | image(必須、添付ファイル ID)、overlay_opacity(10~100、10 刻み、デフォルトは 50)、blocks(必須)、className |
media_text | image(必須、添付ファイル ID)、side(left/right)、blocks(必須)、className |
spacer | height px(1~1000、デフォルトは 100)、className |
chart | chart(必須:bar/horizontal-bar/line/area/pie/doughnut/scatter/radar)、labels string[](scatter を除き必須 — データポイントごとに 1 つ)、datasets(必須、{ label, data } を 1~8 個。data は有限数値で構成し、欠損値には null を指定します。ラベルごとにちょうど 1 つ必要です。scatter の場合は [{ x, y }] で、labels は警告とともに無視されます。pie/doughnut ではデータセットがちょうど 1 つ必要です)、title、caption、unit(目盛り/ツールチップ/テーブルの接尾辞。例:ms、%)、stacked bool、y_min/y_max number、height px(160~800、デフォルトは 320)、source { text?, url? }(「Source: …」として表示)、table(デフォルトの collapsed/open/hidden)、className。文字列はプレーンテキストです(インライン HTML は除去されます)。シリアライズ後の labels + datasets は 64 KB までです。プラグイン v1.77.0。ブロックページでは wpcanai-write-page でも使用できます |
embed を除くすべての種類で className を指定できます(ブロックのルート要素に Tailwind クラスを適用します)。embed は初回保存時に独自のクラスリストを書き換えます。ネストは最大 4 レベルです。ネスト内のエラーでは、ドット区切りの path(例:"2.blocks.0")が報告されます。
画像:まずサイドロードしてから、ID を渡します。 write-post が受け付けるのは添付ファイル ID のみです。URL やバイナリは受け付けません(cover と media_text も同じ ID を受け取り、解決できない場合は invalid_attachment を返します)。wpcanai-sideload-url を呼び出すか(または wpcanai-list-media で既存のものを検索し)、返された id を渡してください。
テキストフィールド内のインライン HTML は、<a href|title|rel|target>、<strong>、<em>、<b>、<i>、<code>、<br>、<s>、<sub>、<sup>、<kbd>、<mark> に制限されています。それ以外は拒否されず、黙って削除されます。段落内の <script> や <iframe> は、いずれにしても無効なブロックコンテンツです。Markdown は受け付けられず、write-post に生 HTML を使用する回避手段はありません。
wpcanai-get-menus(plugin v1.88.0)
- 引数:
{ }。 - 戻り値:
{ "locations": { "primary": { "menu_id", "name", "items" } | null, "footer": { … } | null }, "languages": { "<lang>": { "primary": { "menu_id", "name", "items" } | null, "footer": … } }, "menus": [{ "id", "name", "slug", "assigned_to": ["primary"], "languages": { "<lang>": ["footer"] } }], "legacy_assignments": { "<old location>": <menu id> }, "translations": { "<lang>": { "translated", "total" } } }。項目は{ "id", "title", "type", "object", "object_id", "url", "target", "classes", "description", "attr_title", "icon", "image", "children" }で、生のままで翻訳されていません(見出しのurlは""です)。(v1.89.0)description/attr_title/icon/image(添付ファイル ID。ない場合は0)。languagesにはデフォルト以外のすべての言語が含まれ、翻訳されたデフォルトメニューを使用する場所はnullになります。また、menus[].languagesには言語ごとの割り当てが示されます。translationsは、言語ごとに、その言語独自のメニューが設定されていない場所について、翻訳済みの項目タイトルと説明の数をカウントします。legacy_assignmentsには、1.88 より前の場所名で割り当てられたままのメニューが一覧表示されます(Menus のアップグレードに関する注記を参照)。 - 各場所にすでに設定されているメニューを確認するため、
write-menuの前に呼び出してください。
wpcanai-write-menu(plugin v1.88.0)
- 引数:
{ "location": "primary"|"footer", "items": [{ "title": string, "page"?: int|string, "url"?: string, "target"?: ""|"_blank", "classes"?: string, "description"?: string, "attr_title"?: string, "icon"?: string, "image"?: int, "children"?: [ …same shape ] }], "merge"?: bool, "lang"?: string }—locationとitemsは必須です。各項目には空でないtitleが必要で、page(公開されている任意の投稿タイプの投稿 ID またはスラッグ → スラッグが変更された場合も追従するページ項目)かurl(サイト相対または絶対 URL のカスタムリンク)のいずれか一方のみを指定します。ただし、見出しは例外です。childrenを持つ項目ではどちらも指定できません(ラベルとして表示され、url: ""になります)。ネストは最大 3 階層です。 - (v1.96.0)スラッグによる
page。 まず完全なパス(gallery/auditorium)を照合し、次に公開されているページが 1 件だけ持つ単独のスラッグを照合します。これにより、子ページは自身のスラッグで解決され、移動後も引き続き解決されます。単独のスラッグが同じ場合は、トップレベルのページが優先されます(プラグイン v1.97.1 以降では、公開済みのページも下書きの同名ページより優先されます)。(v1.97.0) 複数の子ページで共有されている単独のスラッグはambiguous_pageになります。メッセージには各ページがpath (ID n)の形式で表示されます。パスまたは ID を指定してください。他の投稿タイプへのフォールバックはなくなりました。ページに存在しないスラッグだけが他の公開投稿タイプで検索されます(そこで複数の投稿が見つかった場合もambiguous_pageになります)。該当するページがない場合はunknown_pageになります。同じスラッグを持つ未添付画像によってページが隠されることはなくなりました。 - (v1.89.0)リッチフィールド。
description(1 行)、attr_title、icon(^[a-z0-9-]{0,64}$に一致する Lucide 名)、image(画像である添付ファイルの ID)。mergeの場合、省略したフィールドは値を保持し、""/0は値をクリアします。 - (v1.89.0)
lang— デフォルト以外の言語スラッグを指定すると、デフォルトのメニューではなく、その言語専用のメニューを指定した場所に書き込みます(言語ごとのメニューを参照)。最初の呼び出しではPrimary (<native name>)/Footer (<native name>)を作成し(同名のメニューがあれば再利用)、その言語に割り当てます。デフォルトの場所には影響せず、結果にはlangが含まれます。デフォルトまたは不明なスラッグ、あるいはネイティブ翻訳のないサイトの場合は、invalid_langになります。 - (v1.93.0)
langとともにcopy_default: trueを指定すると(itemsは指定しません)、その言語専用のメニューを、指定した場所にデフォルトのメニューのコピーとして作成します。ラベル(タイトル、説明)には、保存済みの翻訳があればそれを使用します。ページ項目と投稿項目は元の投稿にリンクされたままとなり、それ以外の項目は現在の URL を持つカスタムリンクになります。その言語専用のメニューがすでに存在する場合はmenu_exists(data:menu_id)、その場所にデフォルトのメニューがない場合はno_default_menu、langが指定されていない場合はinvalid_inputを返します。それ以外のすべての呼び出しではitemsが必須です。 - デフォルトでは置き換えます。 指定した場所の項目は、指定された順序とネストどおりに
itemsと完全に一致するようになります。items: []を指定するとメニューが空になります。merge: trueの場合は既存の項目を保持し、同じ親の下にある同じtitleの項目を更新して、残りを追加します。 - 場所ごとにメニューは 1 つです。 指定した場所にすでに割り当てられているメニューに書き込み、名前は変更しません。メニューが割り当てられていない場所に限り、新しいメニューを
Primary/Footerという名前で作成し、その場で割り当てます。メニューを削除するツールはありません。メニューの削除は管理者が wp-admin で行います。 - 書き込みの前にツリー全体を検証します。
primary/footer以外のlocationは入力検証で拒否されます。エラーには、unknown_page(解決先がないpage。先にページを作成してください)、ambiguous_page(v1.97.0。複数のページで共有されているスラッグ。パスまたは ID を指定してください)、invalid_item(titleがない、pageとurlの両方が指定されている、childrenを持たない項目でどちらも指定されていない、targetが""/"_blank"以外、iconが無効、imageが画像添付ファイルではない)、too_deep(3 階層を超えている)があります。いずれの場合もメニューは変更されません。 - 戻り値:
get-menusが報告する指定場所の状態(menu_id、name、items)に加えて、written(書き込まれた項目数)とpurgedを返します。メニューはすべてのページに表示されるため、書き込みによってページキャッシュ全体が消去されます(ツールラベルを参照)。
wpcanai-assign-menu (plugin v1.89.0)
- 引数:
{ "location": "primary"|"footer", "lang"?: string, "menu_id": int|null }— ロケーション(またはlangを指定して、1つの言語のロケーション)に既存のメニューを割り当てます。IDはwpcanai-get-menusで一覧表示できます。メニュー項目は書き込みません。その場合はwrite-menuを使用してください。 menu_id: nullにすると割り当てが解除されます。言語を指定した場合、その言語は翻訳済みのデフォルトメニューにフォールバックします(その言語独自のメニューは割り当て解除された状態で保持されます)。langを指定しない場合、ロケーションにはメニューが割り当てられなくなり(v1.88 より前のエイリアスエントリーも同様です)、その後wpcanai-scanは、表示箇所ごとにmenu_not_assignedを報告します。- エラー:
unknown_menu(IDがナビゲーションメニューではありません)、invalid_lang(デフォルトまたは不明なスラッグ)。戻り値:{ "location", "lang" (ロケーション自体の場合は null), "menu_id", "name", "items", "purged" }— 直前に行った割り当てです。langを指定した場合、その言語独自のメニューが返されます(解除後はmenu_id: 0ですが、言語には翻訳済みデフォルトメニューが表示されます)。langを指定しない場合は、ロケーションのメニューが返されます。 - サイト所有者が同等の操作を行う場所は、外観 → メニュー → メニューの位置を管理(デフォルト)と CanAI → 翻訳 → メニュー(言語ごと)です。
wpcanai-read-settings
- 引数:
{ "keys"?: string[] }— すべての許可リスト対象オプションを読み取る場合は、keysを省略します。 - 戻り値: オプションのキー → 値のオブジェクト。
- 許可リスト対象キー:
show_on_front、page_on_front、page_for_posts、blogname、blogdescription、users_can_register、wpcanai_default_layout、wpcanai_tailwind_settings(オブジェクト:load_tailwindはyes|no、sourceはcdn|plugin(v1.58.2 以降のデフォルトはplugin)、pluginsは string[])、wpcanai_chart_settings(オブジェクト、plugin v1.77.0:load_chartはauto|yes|no(デフォルトはauto— Chart.js はチャートを表示するリクエストでのみ読み込まれます。yesは CanAI のすべてのページで読み込み、noは読み込みません。チャートは表のみ表示されます)、sourceはplugin|cdn(デフォルトはplugin)。部分オブジェクトは保存済みの設定と統合され、不明な値はデフォルト値として扱われます)、wpcanai_markdown_negotiation("1"|"0"。エージェント向け Markdown を参照)、wpcanai_purge_after_write("1"|"0"、plugin v1.80.0、デフォルトはオン — CanAI が書き込みを行った後にページキャッシュを消去します)、woocommerce_enable_signup_and_login_from_checkout、woocommerce_enable_myaccount_registration、woocommerce_cart_page_id、woocommerce_checkout_page_id、woocommerce_myaccount_page_id、woocommerce_shop_page_id。
wpcanai-update-settings
- 引数:
{ "settings": { "<key>": <value>, ... } }— 許可リスト対象キーのみ(wpcanai-read-settingsと同じ)。page_on_frontを設定すると、該当する場合はshow_on_frontも"page"に設定されます。 - 戻り値:
{ "success": bool, "updated": string[], "rejected": [{ "key", "reason" }] }— (v1.80.0)reasonはnot_whitelisted、invalid_type、invalid_valueのいずれかです。何も更新されなかった場合、呼び出しは失敗し、エラーメッセージに拒否されたすべてのキーが列挙されます。一部のキーが設定された場合はsuccessがtrueになり、残りはrejectedに入ります。必ず確認してください。 - (v1.80.0)ブール値。 オン/オフ設定(
users_can_register、wpcanai_markdown_negotiation、wpcanai_purge_after_write、WooCommerce の登録切り替え設定)は、true/false、1/0、"1"/"0"、"yes"/"no"を受け付けます。このツールおよび他のすべてのツールのブール値入力では、文字列"false"は false として扱われます。 - 読み取り側は引き続き寛容です。 許可リストにないキーのみを指定して
read-settingsを実行すると、エラーにならず許可リスト全体が返されます。データを含むレスポンスが返ってきても、指定したキーの存在確認にはなりません。書き込み時にrejectedを確認してください。
wpcanai-setup
- 引数:
{ }。 - 戻り値:
{ "success": bool, "steps": array }— 各ステップにはaction、status(done|skipped|error)、detail(推奨されるブートストラップの内容:テーマ、レイアウト、ヘッダー、フッター、ホームページ、フロントページのオプション、デフォルトのレイアウト、Tailwind の設定)が含まれます。
wpcanai-get-option
- Args:
{ "name": string }—wp_options.option_name。 - Returns:
{ "name": string, "value": mixed }。 - Errors (v1.89.3):
option_not_readableは、オプション名とその理由を示します。…は MCP の拒否リストに登録されており、MCP 経由では読み取れません — 中止してください。意図的にブロックされており、CanAI がサポートする設定についてはwpcanai-read-settingsで確認できます。…は MCP の読み取り許可リストに登録されていません — CanAI → AI Client → Guardrails で追加する正確な名前をユーザーに伝え、確認後に一度だけ再試行してください。推測で繰り返し試さないでください。 - Policy: 名前は WP Admin → CanAI → AI Client → Guardrails の読み取り許可リストに登録されている必要があります。拒否リストは危険なキー(例:
active_plugins、cron)をブロックします。wpcanai_mcp_で始まる名前は常にブロックされます(MCP の内部情報)。wp-config.phpでWPCANAI_MCP_OPTIONS_UNRESTRICTEDが定義されている場合、拒否リストにない他の名前はすべて読み取ることができます。
wpcanai-update-options
- Args:
{ "options": { "<option_name>": <value>, ... } }— JSON で扱えるスカラー値と配列のみ。 - Returns (applied):
{ "success": true, "status": "applied", "updated": string[], "pending_id": null }。 - Returns (queued):
{ "success": true, "status": "pending_approval", "pending_id": string, "option_keys": string[], "message": string }— 管理者が WP Admin → CanAI → AI Client → Guardrails → Pending MCP option updates で Approve をクリックするまで、データベースへの書き込みは行われません。 - Policy: Guardrails タブで、自動適用リストと承認が必要なリストを設定してください。名前が両方のリストにある場合は、承認が優先されます。リクエスト内に承認が必要なキーが1つでもある場合、
optionsオブジェクト全体が1件の保留中リクエストとしてキューに登録されます。名前は少なくとも1つの書き込みリストに登録されている必要があります(制限なしモードの場合を除く)。拒否リストはget-optionと同じです。
wpcanai-get-pending
- Args:
{ "pending_id": string }—statusがpending_approvalの場合にwpcanai-update-optionsが返す値。 - Returns:
{ "pending_id", "status": "pending"|"unknown", "created_at"?: int, "option_keys"?: string[], "message"?: string }— 承認、拒否、期限切れ、または無効な ID の後はunknownになります。wp-admin でユーザーに承認を依頼した後のポーリングに使用してください。
wpcanai-i18n-get-settings
- Args:
{ }。 - Returns:
{ "default": string, "languages": [{ "slug", "locale", "native_name", "hreflang" }], "enabled": bool, "site_locale": string }— デフォルト以外の言語が1つ以上設定されている場合、enabledはtrueです。(v1.92.0)localeは、その言語が選択されたときの WordPress ロケール(ms_MY)です。WordPress の一覧にない言語、および v1.92.0 より前に保存された言語の場合は""です。(v1.95.0)site_localeは WordPress のサイトの言語(Settings → General。英語(米国)の場合はen_US)で、デフォルト言語は常にこれになります。これはルーターのプローブです。翻訳リクエストでは必ず最初に呼び出してください(翻訳モデルのルーターを参照)。
wpcanai-i18n-set-settings
-
Args:
{ "languages": [{ "slug"?: string, "locale"?: string, "native_name"?: string, "hreflang"?: string }], "default"?: string }—languagesは必須です。言語リスト全体を置き換えます。 新しい言語だけでなく、すべての言語を含めてください。(v1.95.0)defaultは省略可能です。以下のデフォルトはサイトの言語を参照してください。 -
(v1.92.0) WordPress ロケールを渡してください。 各言語には
slugまたはlocale(WordPress ロケール:ms_MY、ja、pt_BR、en_US)が必要です。管理画面の言語選択と同様に、ロケールを指定すると、省略した値が自動的に補完されます。slug:ISO 639-1 コード。同じコードを使用する別の言語がすでにある場合に限り、地域を付加します(ptの後にpt-pt)。native_name:ロケールに対する WordPress 独自の言語名。en_USの場合は「English」です。hreflang:言語コードのみ(ms)。同じコードを使用する別の言語がある場合は、言語コードと地域を指定します(pt-PT)。 つまり、{ "languages": [{ "slug": "en" }, { "locale": "ms_MY" }] }を指定すると、マレー語がms/ Bahasa Melayu /msとして追加されます。既存の言語でlocaleを省略した場合は、保存済みの値が保持されます。"locale": ""を指定するとクリアされます。ロケールがない場合、native_nameとhreflangはスラッグを既定値とします。
-
(v1.92.0)エラー。 いずれのエラーでも設定は変更されず、
error.data.valueに問題のある入力が示されます。unknown_locale:WordPress のロケールではありません。メッセージには近い候補が示されます(「th_TH is not a WordPress locale. Did you mean th?」)。missing_slug:スラッグもロケールも指定されていない言語です。invalid_hreflang:hreflang は正規化され(ms_my→ms-MY)、language[-Script][-REGION]の形式である必要があります。また、x-defaultは拒否されます。duplicate_slug、duplicate_hreflang(大文字と小文字を区別しません)。- (v1.95.0)
default_is_site_language:defaultがサイト言語のスラッグではありません(data:site_locale、default=必須のスラッグ、value)。invalid_defaultに代わるものです。 - (v1.95.0)
site_language_taken:2つ目の言語にサイト言語のロケールが指定されています。既定の言語を翻訳言語にすることはできません。
-
(v1.95.0)既定の言語はサイト言語です。 CanAI 独自の既定の言語はありません。既定の言語(URL プレフィックスなしで、ページの記述に使われる言語)は、WordPress のサイト言語である
site_localeです。呼び出しでは、その言語の行が選択されます。- まずロケールで選択します(指定された値、またはそのスラッグに保存された値)。
- 該当する行がなければ、ロケールのない行のうち、スラッグまたは hreflang がサイト言語と一致するものを選択します(
en_USのサイトでのenなど)。 - それもなければ、警告を付けて WordPress のリストから先頭に追加します。
defaultは検証用としてのみ渡してください。confirm_default_change(v1.92~v1.94)は無視されます。 -
(v1.95.0)既定の言語を変更するには、サイト言語を変更します。 すべての URL が移動します。新しい言語がプレフィックスのないアドレスを引き継ぎ、以前の既定の言語はプレフィックス付きのパス(
/en/)に移ります。移動する内容をユーザーに伝え、事前に確認してください。 その後、次のいずれかを行います。- サイト所有者が 設定 → 一般 → サイト言語 で変更します。言語パックもインストールされます。
- または、
wpcanai-update-options { "options": { "WPLANG": "ms_MY" } }を呼び出します。これには、WPLANG が update-options の許可リストに含まれている必要があります(CanAI → AI Client → Guardrails。含まれていない場合、ツールはoptions_not_allowedを返します)。また、そのロケールの言語パックがインストールされている必要があります(インストールされていない場合、WordPress は以前の値を保持します)。英語(米国)には""を使用します。
どちらの方法でも CanAI は変更に追従します。新しいサイト言語が既定の言語になり(設定されていない場合は WordPress のリストから追加されます)、以前の既定の言語は翻訳言語として残り、削除される言語はありません。次に管理ページを開いたとき、サイト所有者には移動内容が通知されます。その後、
wpcanai-i18n-get-settingsを再度読み取ってください。 -
戻り値: 更新後の設定(
wpcanai-i18n-get-settingsと同じ形式)。次の場合はwarnings: string[]が含まれます。- (v1.95.0) サイト言語の行が追加された場合。
- (v1.95.0) 保存によって既定の言語がサイト言語に変更された場合(v1.95.0 より前に保存され、サイト言語と一致しなかった設定。Languages タブで保存前に警告されるケース)。移動内容も示されます。
- 削除された言語に翻訳が残っている場合。翻訳は保持され、同じスラッグを再度追加すると復元されます。
wpcanai-i18n-list-strings
- Args:
{ "lang": string, "untranslated"?: bool, "search"?: string, "post_id"?: int, "layout"?: bool, "menus"?: bool, "location"?: "primary"|"footer" }—langは必須です(翻訳列に入力されます)。untranslated: trueを指定すると、翻訳が空の文字列のみを保持します。searchはソーステキストに対する、大文字と小文字を区別しない部分文字列フィルターです。(v1.88.0)post_idを指定すると、その投稿(ページまたはテンプレート)で使われている文字列のみを保持します。layout: trueを指定すると、そのレイアウトチェーン(レイアウト、ヘッダー、フッター)の文字列が追加されます。menus: trueを指定すると、メニュー項目のタイトル(および説明、v1.89.0)が追加されます。locationを指定すると、1つのロケーションのみが追加されます。(v1.89.0)langで指定したロケーションにその言語独自のメニューが割り当てられている場合、そのメニューはすでにその言語で書かれているため、何も追加されません。 - Returns:
{ "source": string, "translation": string, "post_ids": int[], "menus": string[], "tags": string[], "placeholders": string[] }のarray。(v1.94.0)tagsは翻訳で保持する必要があるトークンです(["strong"]、["a1","a2"]。ソースのインラインタグは属性なしでsourceに表示されます)。placeholdersは保持する必要がある{names}です。post_idsは、_canai_html/_canai_jsにそのt()ソースを含む投稿です。(v1.88.0)menusは、そのソースを項目のタイトルまたは説明として使っているメニューのロケーション名です(["primary"]。該当するものがない場合は[])。メニューのみの行ではpost_ids: []です。t()のソースは文字列インデックスから取得されます。コンテンツを変更した場合は、まずwpcanai-i18n-rescanを実行してください。メニューのタイトルは呼び出しごとに割り当て済みのメニューから読み取られます。
wpcanai-i18n-set-translations
- Args:
{ "lang": string, "translations": { "<source>": "<translated>", ... } }— 1つの言語に対する一括アップサートです。langは設定済みのデフォルト以外の言語である必要があります(デフォルト言語のテキストがソーステキストです)。空またはnullの翻訳はエントリーを削除します。(v1.94.0) 値では、ソースのタグ(<strong>…</strong>、<a1>…</a1>、<br/>)と{placeholders}を任意の順序で保持する必要があります(言語に合わせて移動できます)。それ以外のマークアップは取り除かれます。タグを削除、追加、重複、交差させた値や、プレースホルダーを削除した値は保存されません。結果のrejected: [{ "source", "reason" }]に記載されます(例:「Missing .」)。savedには、書き込まれたものだけがカウントされます。ソースキーは保存済みのソースと完全一致(文字単位で一致)する必要があります。前後の空白を削除したり、改行や折り返しを変更したりしないでください。 - Returns:
{ "saved": int, "lang": string }。
wpcanai-i18n-get-media-map
- Args:
{ "lang"?: string }— すべての言語を対象にする場合は省略します。 - Returns: 言語スラッグをキーとするオブジェクト:
{ "<lang>": { "<original_attachment_id>": <translated_attachment_id>, ... } }—{{ tmedia(id) }}で使われる、言語ごとの添付ファイルの置き換え情報です。
wpcanai-i18n-set-media-map
- Args:
{ "lang": string, "map": { "<original_id>": <translated_id>, ... } }— 一括アップサートです。デフォルト以外のlangのみ指定できます。0/nullはマッピングを削除します。 - Returns:
{ "lang": string, "map": { ... } }— その言語の更新後のマップ全体です。
wpcanai-i18n-rescan
- Args:
{ }—_canai_html/_canai_jsを持つすべての投稿から文字列インデックスを再構築します。コンテンツを編集した後、およびwpcanai-i18n-list-stringsの実行前に実行してください。 - Returns:
{ "posts_scanned": int }。
wpcanai-i18n-get-post-overrides
- Args:
{ "post_id": int, "lang"?: string }—langを省略すると、すべての言語のデータが返されます。 - Returns:
langを指定した場合は{ "post_id", "lang", "overrides": { title?, content?, excerpt?, fields?: {meta_key: value} } }、省略した場合は{ "post_id", "overrides_by_lang": { "<lang>": {...} } }。空のオブジェクトはオーバーライドがないことを示します(デフォルト言語の値が表示されます)。
wpcanai-i18n-set-post-overrides
- 引数:
{ "post_id": int, "lang": string, "overrides": { "title"?, "content"?, "excerpt"?, "fields"?: { "<meta_key>": "<value>" }, "seo_title"?, "seo_description"? } }— スパースアップサートです。送信されたキーのみが変更されます。値がnull/""の場合、そのオーバーライドは削除され、デフォルト言語にフォールバックします。最終的に空になった blob は行ごと削除されます。contentはHTMLを受け付けます(wp_kses_post)。title/excerptはプレーンテキストです。fieldsの値もプレーンテキストです。seo_title/seo_descriptionはプレーンテキストで、アクティブなSEOプラグインに渡されます(REFERENCE.md → i18n → SEO translationを参照)。デフォルト言語は拒否されます(invalid_lang)。投稿自体がデフォルトです。不明なトップレベルキーは黙って破棄されます。 - 戻り値:
{ "post_id", "lang", "overrides": <resulting blob> }。 - フィールドキーは書き込み時に
sanitize_keyで正規化されます("My_Field"はmy_fieldとして保存/照合されます)。レンダリング時の読み取りパスでも同じように正規化されます。wpcanai-i18n-set-translationsのsavedは、書き込み済みのペアではなく、送信されたペア(削除対象やスキップされた非文字列を含む)の数をカウントします。
wpcanai-i18n-get-term-overrides
- 引数:
{ "term_id": int, "lang"?: string }。 - 戻り値: 投稿版と同じ形式で、blobキーは
name/descriptionです。
wpcanai-i18n-set-term-overrides
- 引数:
{ "term_id": int, "lang": string, "overrides": { "name"?, "description"?, "seo_title"?, "seo_description"? } }— 投稿版と同じスパース/削除/デフォルト言語のセマンティクスです。descriptionはHTMLを受け付けます(投稿のcontentと同様にwp_kses_post)。nameはプレーンテキストです。seo_title/seo_descriptionはプレーンテキストで、アクティブなSEOプラグインに渡されます(REFERENCE.md → i18n → SEO translationを参照)。 - 戻り値:
{ "term_id", "lang", "overrides": <resulting blob> }。
グローバル文字列 — 投稿に紐づかないサイトレベルの文言
サイト名、キャッチフレーズ、アーカイブ/検索/404のSEOタイトルと説明文は、言語ごとのグローバル文字列ストア(オプションwpcanai_i18n_global_strings)に保存されます。これらは単一の投稿に属さないため、投稿/タームのオーバーライドとは別です。デフォルト以外の言語のフロントエンドでは、これらの文字列がoption_blogname/option_blogdescriptionとog:site_name(サイト名/キャッチフレーズ)、およびアーカイブコンテキストsearch、404、post_type:<slug>の<title>とメタディスクリプションに反映されます。タームアーカイブ(カテゴリー/タグ/カスタムタクソノミー)はグローバル文字列のコンテキストではありません。これらにはwpcanai-i18n-set-term-overridesを使用します。
wpcanai-i18n-get-global-strings
- 引数:
{ "lang"?: string }— すべての言語を取得するにはlangを省略します。 - 戻り値(
lang指定時、対象言語のみ):{ "lang": string, "strings": { "site_name": string, "tagline": string, "archive": { "<context>": { "title", "description" } } } }。未設定の場合、site_name/taglineは""です。戻り値(すべての言語、lang省略時):{ "by_lang": { "<lang>": <blob> } }。読み取り専用です。
wpcanai-i18n-set-global-strings
- 引数:
{ "lang": string, "values": object }— 両方必須です。valuesのキーは、site_name(プレーンテキスト)、tagline(プレーンテキスト)、archive(コンテキストから{ "title"?, "description"? }へのマップ)です。スパースアップサートです。送信されたキーのみが変更されます。値がnull/""の場合、そのキーは削除されます。最終的に空になったblobは言語の行ごと削除されます。デフォルト言語は拒否されます(invalid_lang)。サイト独自の名前/キャッチフレーズがデフォルトです。アーカイブコンテキストはsearch、404、post_type:<slug>(例:post_type:product)です。タームアーカイブ(カテゴリー/タグ/カスタムタクソノミー)はグローバル文字列のコンテキストではありません。これらの翻訳にはwpcanai-i18n-set-term-overridesを使用してください。 - 戻り値:
{ "lang": string, "values": <resulting blob> }。
wpcanai-i18n-list-content
- 引数:
{ "lang": string, "post_type"?: string, "untranslated"?: bool }— コンテンツ作業キューです。langには、設定済みのデフォルト以外の言語を指定する必要があります(デフォルト言語はソースコンテンツです。指定するとinvalid_inputエラーになります)。attachmentを除く公開投稿タイプの公開済み投稿が対象です(最大 1000 行。不明なpost_typeを指定すると[]を返します。投稿数の多いサイトではpost_typeで絞り込んでください)。 - 戻り値:
{ "id", "title", "post_type", "status", "kind", "done"?, "total"? }のarrayです。(v1.91.0)kindに応じて、投稿一覧の「翻訳」列および CanAI → 翻訳 → コンテンツと同じルールを適用します。kind: "content"(CanAI Twig ページ以外のすべての投稿):オーバーライドの blob です。statusは、blob がない場合はuntranslated、投稿本文が空でないのにcontentのオーバーライドを含まない blob がある場合はpartial、それ以外はtranslatedです。kind: "strings"(空白でない_canai_htmlを持つ CanAI Twig ページ):ページ独自のt()ソースです。レイアウトは対象外です。done/totalは、翻訳済みの件数を表します。statusは、すべて翻訳済みの場合はtranslated、一部の場合はpartial、翻訳済みがない場合はuntranslated、ページにt()文字列がない場合はnothingです。タイトルのオーバーライドだけでは、Twig ページは「翻訳済み」になりません。- v1.91.0 より前は、すべての行で blob のルールが使われ、
kindは含まれていませんでした。 untranslated: trueを指定すると、未翻訳と一部翻訳済みの行だけを返します。nothingは返しません。
wpcanai-i18n-get-content
- 引数:
{ "post_id": int, "fields"?: ["meta_key", ...], "lang"?: string }—post_idは必須です。fieldsには、含めるカスタムフィールドのメタキーを指定します(sanitize_keyで正規化されます。オーバーライドの保存方法と同じです)。省略可能なlang(設定済みのデフォルト以外の言語)を指定すると、その言語の現在のオーバーライド blob も並べて比較できるよう返されます。 - 戻り値:
{ "post_id": int, "post_type": string, "source": { "title": string, "content": string, "excerpt": string, "fields": { "<meta_key>": value }, "seo": { "title": string, "description": string } }, "overrides"?: { "<lang>": blob } }—sourceはデフォルト言語の RAW コンテンツです(タイトル/本文/抜粋は投稿から直接読み取り、指定されたカスタムフィールドはメタデータから読み取ります。seoは有効な SEO プラグインから読み取ったデフォルト言語の SEO タイトル/説明です)。読み取り専用です。これは、wpcanai-i18n-set-post-overridesを呼び出す前にエージェントが翻訳するソースを取得する、eval を使わない方法です。
プリセット — wpcanai-list-presets / wpcanai-install-preset / wpcanai-uninstall-preset
wpcanai-list-presets→{ presets: [{ slug, title, description }] }。同梱パック(例:cpt-corporate、single-freelancer、blog-journal— ブログ全体を構成し、Blog ページが「Reading → Posts page」になります)は、完全なテンプレートスタック(レイアウト/ヘッダー/フッター+型付きのsingle-*/archive-*テンプレート)を構築します。wpcanai-install-preset—{ "slug": string, "set_front_page"?: bool, "clean_slate"?: bool, "adopt_woo_pages"?: bool, "trash_woo_pages"?: bool }。パックのテンプレートとページをインストールし、画像をサイドロードします。また、(v1.26+)ユーザー向けのコピーを{{ t('…') }}で囲み、languages()スイッチャーを追加します。ネイティブの i18n StringIndex が事前に読み込まれるため、インストール後に言語を設定した場合でも、wpcanai-i18n-list-stringsにパックの文字列がすぐに表示されます。パックのテンプレートでは{{preset.image_id.<key>}}を参照して、tmedia()用のサイドロード済み添付ファイル ID を取得できます。- ⚠
clean_slate: trueは破壊的な操作です。 インストール前に、既存の CanAI テンプレートとページをすべてゴミ箱に移動し(ゴミ箱から復元できます)、プリセットの管理情報を消去します。この処理は、その後のインストールに失敗した場合でも実行されます。ユーザーの明示的な確認なしに、決して指定しないでください。MCP ホストでは、組み込みのガードなしで、このブール値がツールスキーマに公開されます。 adopt_woo_pages(デフォルトはtrue、v1.47.0)。settings.woo_pagesを持つパックは、重複ページ(checkout-2など)を作成せずに、ストアの既存の WooCommerce ページにコンテンツを書き込みます。これにより、ページ ID とパーマリンクが維持され、すでに送信済みのメール内にある注文受領 URL も引き続き機能します。各ページの以前の CanAI メタデータはスナップショットとして保存され、wpcanai-uninstall-presetによって復元されます。ページ自体が削除されることはありません。falseを指定すると、新しいページが強制的に作成されます(v1.47.0 より前の動作。以前に発行した注文リンクは機能しなくなります)。trash_woo_pages(デフォルトはfalse)。 既存のショップ/カート/チェックアウト/マイアカウントのページをゴミ箱に移動し(ゴミ箱から復元できます)、パック独自のストアページにそれらのスラッグを割り当てます。この処理は引き継ぎより先に実行されるため、優先されます。引き継ぎ時には枠が空になっており、新しいページが作成されます。
- ⚠
wpcanai-uninstall-preset—{ "slug": string }。パックのテンプレートとページを削除し、作成したナビゲーションメニューをすべて削除します。
wpcanai-export / wpcanai-import
wpcanai-export→ CanAI のテンプレートとページ(メタデータ_canai_html/css/js/context/layout)をまとめた JSON バンドルで、各行のi18n_metaキーにより、すべての_canai_i18n_{lang}コンテンツ上書きデータを往復処理できます。(v1.39.0) コンパイル済みビルドがある行には、プリコンパイル済み Tailwind キャッシュ(_canai_tailwind_build/_hash/_built_at)も含まれます(空でないビルドのみエクスポートされ、ソース相対の_canai_tailwind_epochスタンプは除外されます)。これにより、インポートしたレイアウトは Play CDN にフォールバックせず、インラインでレンダリングされます。メディアバイナリは含まれません — 添付ファイル ID には再サイドロード用のフラグが付けられ、自動的に再マッピングされることはありません。(v1.65.0) ブロックで作成したページも含まれません — エクスポート対象は_canai_htmlが空でない投稿のみのため、ブロックで作成したページ(本文がpost_contentにあるもの)はバンドルに含まれません。完全なバックアップ範囲を約束しないでください。(v1.80.0){ "summary": true }を指定すると、バンドルの代わりにインベントリを返します —{ templates: [{ id, title, type, status, hashes }], pages: [{ id, title, format, hashes }], counts: { templates, pages, terms }, version }。これはread-metaが返すものと同じ SHA-1hashesで、コンテンツは含まれません。2 つのサイトの比較や、取得前に変更内容を確認するために使用します。wpcanai-import—{ "data": object | "json": string, "dry_run"?: bool }。dry_run: trueを指定すると、書き込みを行わずに変更内容を報告します。上書きデータはインポート時に再サニタイズされます。認証ゲート: インポートではunfiltered_htmlレベルの書き込みが行われます。呼び出し元にunfiltered_html権限(単一サイトでは管理者に付与されています)がない場合、またはリクエストに有効な CanAI API キー(Bearer /X-WPCanAI-API-Key)が含まれていない場合、403forbiddenが返されます。- (v1.97.0)パスによるページ指定。 バンドルはバージョン 1.1(
wpcanai_export_version)です。各ページ行にはpost_nameと並んでpath(gallery/auditorium)が含まれ、委譲先ページの参照にもpathが含まれます。インポートでは既存ページのみ更新され、新しいページは作成されません。WooCommerce のページ行は、まずストア内でそのタイプに該当するページと照合されます。それ以外の場合、バージョン 1.1 の行は完全一致するpathのみと照合されます(他の場所にある同名ページを上書きする可能性があるため、単独のスラッグへのフォールバックはありません)。古いバンドルの行は、サイト内でどの親の下にあるかを問わず、そのスラッグを持つページが 1 つだけの場合に限り、スラッグで照合されます。ページが見つからない行、または(古いバンドルの場合)複数のページで共有されているスラッグを持つ行は、警告とともにスキップされます(pages_skippedにカウントされ、page_actionsではaction: "skipped")。パスが見つからない場合、同じスラッグを持つページが 1 つあれば、その場所が示されます。wpcanai-update-pageでその場所に移動してから、もう一度インポートしてください。スラッグが共有されている場合は、各ページがpath (ID n)の形式で一覧表示されます。その場合は、CanAI 1.97+ からもう一度エクスポートしてください。pathを含む委譲先参照は、そのパスのみで解決されます。該当ページが見つからない場合、そのページは委譲先ページなしでインポートされ、その旨が警告されます。(v1.97.1) 古いバンドルの委譲先参照(pathなし)は、スラッグを持つページまたは投稿が 1 つだけの場合に限り解決されます。インポート前に、wpcanai-create-page(parentを指定)で不足しているページを作成してください。
wpcanai-diagnostics
- 引数:
{ "include_network"?: bool }(デフォルトはfalse)。→ wp-admin の Diagnostics ページを反映したヘルスレポートです(PHP/WP/プラグインのバージョン、機能とエンドポイントのチェック、Tailwind のビルド状況、WooCommerce の有無と HPOS の安全性に関する注記)。 include_network: trueを指定すると、実際の外部 HTTP リクエスト(外向き HTTPS、REST ループバック、skills エンドポイントへの到達性、認証ヘッダーの引き継ぎ)も実行します。時間がかかります。推測で判断するのではなく、接続性や環境の問題が疑われる場合に使用してください。- (v1.80.0)
page_cacheチェック(プラグインの検出、パージフック、自動パージのオン/オフ)と、integrationsグループ(ツールラベルごとに 1 行:有無、登録されたツール数、無効かどうか)が追加されました。(v1.82.0)integrationsの各行では、ツール数を 宣言された ラベル(touches+requires)に基づいて集計します。そのため、統合機能が存在しなくても、それを宣言しているツールの数が報告され、hidden_by_recommendationも含まれます。 - (v1.82.0)
toolsグループ:tool_budget(公開中と全ツールの数、バイト数、約トークン数)とtool_recommendations(「Follow recommendations」がオフで、推奨設定が現在の状態と異なる場合に警告します。fixは正確なmanage-tools呼び出しです)。languagesグループ:languages(設定されているネイティブ言語、またはなし)とtranslation_tools(Languages ツールグループと、言語リストとの組み合わせ)があります。言語なし/オフ → パス(未使用)、言語なし/オン → 警告(i18n-set-settingsで言語を追加するか、グループをオフにします)、言語あり/オン → パス、言語あり/オフ → 情報(正当なオーナーの選択です。翻訳が必要な場合はmanage-toolsで有効にします)。診断で翻訳に触れるのはここだけです。有効化しない限り、ほかの箇所では翻訳について言及されません。 - (v1.90.0)
renderグループ:過去 7 日間にテンプレートでレンダリング警告が発生していない場合はpassの行を表示します。それ以外の場合は、各項目につきwarningの行を 1 行ずつ表示します(新しい順、最大 10 件。その後に残りの件数を示すinfoの行を表示)。各行にはpost_id、field、line、edit_urlが含まれます。これはwpcanai-scanがrender_warningとして報告する項目と同じです。 - (v1.88.0)
menusグループ:場所ごとに 1 行表示します。メニューが設定されている場合は、メニュー名と項目数を含むpass、何も割り当てられていない場合はwarning(fixはwrite-menu呼び出し)を表示します。また、以前の v1.88 より前の場所名で割り当てられたままのメニューを一覧表示するinfoの行も表示します。(v1.89.0) 言語メニューごとに、さらにinfoの行を 1 行表示します(「メニューの場所:footer(Bahasa Melayu)」)。
wpcanai-purge-cache(プラグイン v1.80.0、cache が必要)
- サポート対象のキャッシュプラグインが有効な場合にのみ使用できます(LiteSpeed Cache、WP Rocket、W3 Total Cache、WP Super Cache、ページキャッシュがオンになっている WP-Optimize — v1.82.0)。該当するプラグインがなければ、オフが推奨され、通常はリストに表示されません(ルール R1)。パージするのは サードパーティのページキャッシュ のみです。CanAI の Twig コンパイルキャッシュと Tailwind ビルドは、ソースが変更されるたびに自動で無効化されるため、パージは不要です。
- 引数:
{ "scope": "all"|"url"|"post", "target"?: string|int }—urlの場合、targetは URL(このサイト上の URL である必要があります)、postの場合は投稿 ID です。allの場合は無視されます。 - 戻り値:
{ "purged": [{ "scope", "target" }], "plugin": "litespeed"|"wp-rocket"|"w3tc"|"wp-super-cache"|"wp-optimize"|null, "note"? }。plugin: nullは、サポート対象のキャッシュプラグインが検出されなかったことを意味します。エラーではありません。その場合、機能するのはpostのみ(WordPress の投稿キャッシュをクリア)で、all/urlは注記を返します。 - 通常は呼び出す必要はありません。 書き込み後のパージがオン(
wpcanai_purge_after_write、デフォルトでオン)の場合、CanAI の書き込みはすべてリクエストの最後に 1 回パージします。テンプレートの変更ではサイト全体、ページの変更ではそのページがパージされ、書き込みのpurgedフィールドにその旨が示されます(ツールラベルを参照)。purge-cacheを呼び出すのは、キャッシュプラグインが有効なのにpurgedがnullだった場合(自動パージがオフ)、または書き込みの対象外だった URL(例:編集したページを一覧表示するアーカイブ)に限ってください。
Google Stitch の画面をデプロイする → canai-stitch スキル
Google Stitch のデプロイ(CanAI Stitch アドオンの wpcanai-stitch-connect、-list-projects、-set-projects、-list-screens、
-deploy-screen ツール)には、専用のスキル canai-stitch(npx skills add usewp/canai --skill canai-stitch)があります。
「Stitch をソースのままにする」か「CanAI に引き渡す」かの選択、stitch_page_edited ガードを使ったデプロイと再デプロイのワークフロー、忠実なコピーを CanAI の規約に合わせるためのクリーンアップについて解説しています。Stitch に関する依頼では必ず読み込んでください。オーナーから編集内容を置き換えるよう依頼されていない限り、wpcanai-stitch-deploy-screen に overwrite: true を指定しないでください。
メディアのアップロード
方法は 2 つあります。ソースに応じて選んでください。
| ソース | 使用する方法 | 理由 |
|---|---|---|
画像がすでに URL になっている(https://…/photo.jpg — 例:ソースサイト、CDN、レプリカのキャプチャからのホットリンク) | MCP ツール wpcanai-sideload-url | サーバーがデータを取得するため、MCP 経由で送るのは小さな JSON のみです。API キー/ベース URL/curl は不要です。こちらを推奨します。 |
| ローカルのバイナリファイル(ユーザーのマシン上にあるファイルで、公開 URL がないもの) | sideload REST エンドポイント(以下) | MCP はバイナリペイロード(サイズと Base64)の送信には適していません。 |
URL の画像 → wpcanai-sideload-url(推奨、MCP のみ)
MCP ツールを呼び出します。認証情報を用意する必要はなく、認証済みの MCP トランスポート経由で実行できます。
wpcanai-sideload-url {
"url": "https://example.com/images/hero.jpg",
"alt": "Front of the product", // optional
"attach_to": 0 // optional parent post id
}
任意の項目:filename、title、caption、description。戻り値は { id, source_url, mime_type, filename, attached_to } です。_canai_html を記述するときは、返された id を {{ image_attrs(id, 'src,alt') }} / {{ media_url(id, 'full') }} 経由で使用してください(レンダリング時に解決されます。「CanAI のテンプレート関数を優先する」原則を参照)。絶対 URL が必要な場合(OG/Twitter メタ、Web マニフェスト)に限り、絶対 URL の source_url を使用してください。アセットがホットリンクされた URL であるレプリカ/インポートの処理には、この方法が適しています。
ローカルのバイナリファイル → sideload REST エンドポイント
MCP メッセージはバイナリペイロード(サイズと Base64 のオーバーヘッド)の送信には適していません。代わりに sideload REST エンドポイントを使用してください。MCP トランスポートと同じ CanAI API キーを使用できるため、別の認証情報は必要ありません。
- エンドポイント:
POST {site}/wp-json/wpcanai/v1/sideload - 認証:
Authorization: Bearer <wpcanai_…API key>(またはX-WPCanAI-API-Key:)。 - 本文:
multipart/form-data。必須フィールドはfile=@<local-path>です。任意の項目:filename、title、alt、caption、description、attach_to(親投稿 ID)。 - 戻り値:
{ id, url, source_url, mime_type, filename, title, alt, attached_to }。 - API キーのユーザーに必要な権限:
upload_files(管理者にはこの権限があります)。
ワークフロー(画像は 1 枚ずつ)
静的サイトのインポート(ユーザーが /canai-mcp implement <folder> などを実行した場合)では、確認せず、参照されているアセットを自動検出して、事前処理としてサイドロードしてください。「HTML を実装 → CanAI」の「静的サイトのアセットを事前処理でサイドロードする」を参照してください。以下の手順は、そのワークフロー以外で単一ファイルを都度アップロードする場合に適用します。
-
ユーザーがローカルファイルのパスをまだ提示していない場合は、パスを尋ねます。
-
各ファイルをユーザーのマシンから 1 つずつ POST します。こうすることで、それぞれの
idを取得できます。もっとも簡単な方法はcurlで、これはシェルの使用が認められている唯一の例外です。curl -sS -X POST "{site}/wp-json/wpcanai/v1/sideload" \ -H "Authorization: Bearer <API key>" \ -F "file=@/abs/path/to/image.jpg" \ -F "alt=Front of the product"Node のみのスタック(curl も Python もなく、Node 18 以降でグローバルに
fetch/FormData/Blobを利用できる環境。「ローカルスクリプト用の補助コード」を参照)の場合、依存関係なしで同等の処理を実行できます。node -e "const fs=require('fs');const f=new FormData();f.append('file',new Blob([fs.readFileSync(process.argv[1])]),require('path').basename(process.argv[1]));f.append('alt',process.argv[2]||'');fetch(process.argv[3]+'/wp-json/wpcanai/v1/sideload',{method:'POST',headers:{Authorization:'Bearer '+process.argv[4]},body:f}).then(r=>r.text()).then(console.log)" /abs/path/to/image.jpg "Front of the product" "{site}" "<API key>" -
返された
idを取得し、既存の MCP ツール経由でテンプレートに渡します。固定 URL を使うより、_canai_html(wpcanai-write-meta)では{{ image_attrs(id, 'src,alt') }}/{{ media_url(id, 'full') }}を優先してください。絶対 URL が必要な場合(OG/Twitter メタ、Web マニフェスト)に限り、絶対 URL のurlを使用してください。
ファイルを Base64 にエンコードして MCP ツールの引数に渡そうとしないでください。このエンドポイントを使用してください。
メディア SEO の整理(wpcanai-list-media / wpcanai-get-media / wpcanai-update-media)
名前の不適切なアップロードファイルや、代替テキストが設定されていないメディアを整理します(プラグイン 1.45.0 以降)。
- 監査 —
wpcanai-list-media { "missing_alt": true }および/または{ "generic_filename": true }(IMG_4521.jpgのようなカメラ/スクリーンショットのファイル名)。page/per_pageでページネーションします。 - コンテキストの確認 —
wpcanai-get-media { "id": 123 }は、すべてのメタデータに加えて、ファイルを参照しているページを示すused_inを返します。まず、それらのページを読んでください — 代替テキストとファイル名は、画像がそのページのコンテキストで何を示しているかを表す必要があります。古いファイル名から代替テキストを決めてはいけません。 - 修正 —
wpcanai-update-media { "id": 123, "alt": "…", "title": "…", "filename": "red-leather-office-chair" }。filenameは拡張子を含まないスラッグです。ファイルとすべてのサイズバリエーションがディスク上でリネームされ、すべての内部参照が書き換えられます(post_content +_canai_html/_canai_css/_canai_jsメタデータ)。- その後、古い URL は 404 になります(リダイレクトなし)— 変更後に
used_inのページが正しく表示されることを再確認してください。 - 空文字列を明示すると、フィールドがクリアされます。メタデータのみの更新ではファイルに変更を加えません。
- ローカルファイルのみが対象です。外部ストレージ(S3/CDN)上のメディアでは
file_missingが返されます。
重大:CanAI のストレージモデル
CanAI は Twig 本文に post_content を使用しません。_canai_html、_canai_css、_canai_js、_canai_context、_canai_layout には、wpcanai-read-meta/wpcanai-write-meta を使用してください。blocks とマークされたページは例外で、本文は post_content ですが、このスキルでは書き込みません。
重大:コンテンツの解決
WC のショップ/カート/チェックアウト/マイアカウント/商品カテゴリーのコンテンツは、多くの場合 WC ページにあります。商品/404/検索/アーカイブのコンテンツは、多くの場合 wpcanai_template にあります。誤った投稿を編集する前に、wpcanai-resolve-content-id を使用してください。
翻訳モデルの振り分け
CanAI の翻訳モデルは 1 つだけです。ネイティブ文字列翻訳(ページごとに 1 投稿、サイト全体の文字列テーブル、プラグイン 1.22.0 以降)です。言語ごとに投稿を複製する方法は CanAI のモデルではありません — テンプレートとページは言語ごとに分けられていません。投稿を対象とするツール(list-templates、read-meta、write-meta、create-page、write-post など)は lang 引数を受け取らず(誤って指定された引数は無視されます)、lang キーも返しません。lang が登場するのは i18n-* ツールだけで、その場合は翻訳対象の言語を示します。「このサイト/ページを翻訳して」「言語を追加して」「多言語化して」「ローカライズして」など、どのような翻訳依頼でも、まず設定を確認してください。
- (v1.82.0)
i18n-*ツールはオプトイン方式で、デフォルトでは非表示です。wpcanai-i18n-get-settingsがツール一覧にない場合も、翻訳はサポートされていないと伝えないでください。wpcanai-manage-tools { "action": "list" }を実行し、このサイトで翻訳を有効にするかユーザーに確認してから、{ "action": "set", "groups": { "Languages": "on" } }を実行し、再接続してから続行してください。 wpcanai-i18n-get-settings { }を呼び出します。enabled: true→ 以下のネイティブ文字列翻訳に従います。言語ごとの投稿を作成してはいけません。enabled: false→ ネイティブ翻訳はオフです。使用する言語をユーザーに確認します(例:WordPress ロケールのms_MY)。デフォルトは常にサイト言語(site_locale、v1.95.0)で、ページがすでに書かれている言語にする必要があります。異なる場合はその旨を伝え、まずサイト言語を変更してもらってください(wpcanai-i18n-set-settings→ デフォルトの変更はサイト言語の変更を意味します)。次に、言語ごとにlocaleを渡してwpcanai-i18n-set-settingsで初期設定を行い、CanAI にスラッグ、名前、hreflang(v1.92.0)を設定させてから、ネイティブのワークフローを続行します。
ネイティブ文字列翻訳(単一投稿の i18n)
実行するタイミング: 上記のルーターがネイティブモデルと判定した場合です。ユーザーがサイトまたはページの翻訳、言語の追加、未翻訳箇所の補完、画像のローカライズを依頼し、wpcanai-i18n-get-settings が enabled: true を返した場合(または、初期設定を行った直後)に実行します。
モデル(プラグイン 1.22.0 以降): ページ/テンプレートごとに投稿は1つで、言語ごとのコピーは作成しません。ユーザーに表示される文字列は _canai_html / _canai_js 内で {{ t('…') }} にラップされ、サイト全体の文字列テーブルからレンダリング時に解決されます。デフォルト以外の言語はパスプレフィックス(/ms/plt/)付きで提供され、デフォルト言語にはプレフィックスが付きません。wp_head で hreflang の alternate が出力され、tmedia() マップによって言語ごとに添付ファイルが切り替わります。
ワークフロー
-
設定 —
wpcanai-i18n-get-settings { }を実行します。言語が不足している場合や設定が誤っている場合は、ユーザーに確認してからwpcanai-i18n-set-settingsで書き込みます(リスト全体が置き換えられるため、すべての言語を含めてください)。デフォルトはサイトの言語です(v1.95.0)。別の言語をデフォルトにするにはサイトの言語を変更する必要があり、変更するかどうかはユーザーが決めます。 -
作成の前提条件 — ユーザーに表示される文字列はすべて
{{ t('…') }}にする必要があります。 インデックス化されて翻訳可能になるのはt()のソースだけです。ページにハードコードされた文字列がある場合は、先にラップします。wpcanai-read-meta→ 置換ペアを作成 →wpcanai-replace-in-metaの順に実行します。例:{ "post_id": <id>, "replacements": [{ "from": ">Shop now<", "to": ">{{ t('Shop now') }}<" }] }(一致箇所が一意になるよう、周囲のマークアップも含めて指定します)。(v1.94.0)文ごとにt()を1つ使用し、その中にインラインタグを含めます。{{ t('Get <strong class="font-semibold">free shipping</strong> today.') }}のように記述し、{{ t('Get') }} <strong>{{ t('free shipping') }}</strong> {{ t('today.') }}のようにはしません。言語によって語順が異なり、断片を並べ替えられないため、翻訳者には文全体が必要です。- 内側に含めるのはインライン要素(
strong、em、a、span、br、codeなど)だけです。ブロック要素(p、div、li、見出し)は外側に置き、ブロックごとにt()を1つ使用します。 - 動的な値は
{placeholders}として渡す変数です。例:{{ t('Read our <a href="{url}">terms</a>.', {url: turl('/terms/')}) }}、{{ t('By {name}', {name: post.author.display_name}) }}。 - 翻訳対象の属性(
title、aria-label)には、それぞれ専用のt()を使用し、変数として渡します。 - フレーズ全体にスタイルを適用する場合は、これまでどおりにします:
<strong>{{ t('Best seller') }}</strong>。 - 文字列キーには属性を含めません(
Get <strong>free shipping</strong> today.)。そのため、スタイルを変更しても翻訳は維持されます。同じタグが繰り返される場合は番号を付けます(<a1>、<a2>)。
断片の結合。
wpcanai-scanがsplit_sentenceを報告した場合、文が分割されたままです。wpcanai-replace-in-metaで断片全体を1つのt()に結合し、タグをその中に含めます。その後、wpcanai-i18n-rescanを実行し、i18n-list-strings { "post_id": … }から取得した以前の断片の翻訳を参考に、新しいキーを翻訳します。以前の断片キーはテーブルに残りますが、使用されません。ネイティブ i18n が有効なサイトで新しいページを作成する場合は、最初からユーザーに表示される文字列をt()でラップします(Implement HTML → CanAI のヘルパーテーブルを参照)。 -
インデックスを再構築する — コンテンツを編集した後は、
wpcanai-i18n-rescan { }を実行します。wpcanai-i18n-list-stringsが読み取るのはライブのメタデータではなくインデックスです。インデックスが古いと、古い文字列が表示されます。 -
翻訳 — デフォルト以外の言語ごとに、1 ページずつ:
wpcanai-i18n-list-strings { "lang": "ms", "post_id": 42, "layout": true, "menus": true, "untranslated": true }— そのページのt()文字列、レイアウトの文字列(ヘッダー、フッター)、未翻訳のメニュー項目タイトルを取得します。まずはこちらを使います。サイト全体の一覧{ "lang": "ms", "untranslated": true }は、ユーザーがサイト全体を求めた場合にのみ使用してください。- すべての
sourceを自分で翻訳します(エージェントが翻訳を作成します)。メニュー項目のタイトルと説明は通常の source です(menusが["primary"]または["footer"]の行)。同じ呼び出しで翻訳すると、get_menu()が翻訳済みの項目を表示します。テンプレートでt()を使う必要も、再スキャンもありません。その言語専用のメニューが設定されているロケーションは一覧に含まれません。そのメニューはすでにその言語で作成されているためです(「言語ごとのメニュー」を参照)。 - 一括呼び出し 1 回で書き込みます:
wpcanai-i18n-set-translations { "lang": "ms", "translations": { "Shop now": "Beli sekarang", "Add to cart": "Tambah ke troli" } }。 - ユーザーが確認できるよう、source → 翻訳の表を報告します。修正も別の一括呼び出しで行います。
- オーナーもページの「Translate strings」ボタンから同じ操作ができます(プラグイン v1.88.0):ページエディターの「Translations」ボックス、CanAI エディター、ブロックページの CanAI サイドボックス、およびフロントエンドの管理バーにある 「Translate this page」から利用できます。(v1.91.0)「All Pages」/「All Posts」/「All Templates」では、「Translations」列に言語ごとのチップが表示されます。
MSは翻訳済み、MS•は一部翻訳済み、+ MSは未翻訳、—は翻訳対象なしを示します。各チップをクリックすると、該当するエディターが開きます。これにより「Translate: {language}」および「Translate strings」の行アクションは置き換えられました。該当ページに絞り込まれた「CanAI → Translations → Strings」が開き、レイアウトとメニューの切り替えもできます。手動で翻訳したいユーザーにはこちらを案内してください。
-
コンテンツ(CPT/長文コンテンツ)— デフォルト以外の言語ごと:
wpcanai-i18n-list-content { "lang": "ms", "untranslated": true }→ タイトル/本文/フィールドがデフォルト言語のまま表示される投稿の作業キューです。(v1.91.0)kind: "strings"の行は CanAI Twig ページです。上書きではなく、手順 4 に従ってt()文字列を翻訳してください(i18n-list-strings { "lang": "ms", "post_id": <id> }→i18n-set-translations)。以下の手順はkind: "content"の行を対象としています。- 投稿ごとに
wpcanai-i18n-get-content { "post_id": <id>, "fields": ["subtitle", ...] }を実行すると、デフォルト言語の rawsource(title、content、excerpt、名前付きカスタムfields)が返されます。翻訳したら、wpcanai-i18n-set-post-overrides { "post_id": <id>, "lang": "ms", "overrides": { "title": "…", "content": "…", "excerpt": "…", "fields": { "subtitle": "…" } } }を 1 回実行します。(i18n-get-contentに"lang": "ms"を渡すと、既存の上書きも並べて確認できます。)専用の i18n ツールを使用し、コンテンツの翻訳に PHP eval を使わないでください。 - ループ/アーカイブに表示されるタクソノミー用語:用語ごとに
wpcanai-i18n-set-term-overridesを実行します。 - 投稿ごとのカバレッジ表(id → 変更前/変更後のステータス)を報告します。URL は変わりません。上書きされたフィールドを使って、同じ投稿が
/ms/…に表示されます(言語ごとのコピーは作成されません)。 - SEO メタデータ(タイトル/説明)は、
seo_title/seo_descriptionの上書きキーで翻訳します。source はi18n-get-contentで取得してください(SEO ブリッジの動作の詳細は references/REFERENCE.md を参照してください)。これらのキーが必要なのは、SEO 用の文言を表示されるタイトル/本文と異なるものにする場合のみです。それ以外の場合、デフォルト以外の言語のページでは、seo_title/seo_descriptionは翻訳済みのtitle/nameとexcerpt/タグを除去したcontentから自動生成されます(説明は単語の区切りを維持しながら最大 160 文字に切り詰められます)。
-
サイトレベルの文字列(サイト名/キャッチフレーズ/アーカイブの SEO)— デフォルト以外の言語ごと:
wpcanai-i18n-get-global-strings { "lang": "ms" }→ 現在のサイト名、キャッチフレーズ、アーカイブマップを取得します。- 翻訳してから、1 回の呼び出しで書き込みます:
wpcanai-i18n-set-global-strings { "lang": "ms", "values": { "site_name": "…", "tagline": "…", "archive": { "search": { "title": "…", "description": "…" }, "404": { "title": "…" } } } }。 - アーカイブのコンテキストは
search、404、post_type:<slug>です。カテゴリー/タグ/タクソノミーのタイトルはタームのオーバーライド(手順 5)であり、グローバル文字列ではありません。
-
メディア(言語ごとに異なる画像が必要な場合) —
wpcanai-sideload-urlでローカライズしたアセットをアップロードし、マッピングします:wpcanai-i18n-set-media-map { "lang": "ms", "map": { "123": 456 } }。テンプレートでは、その画像を{{ tmedia(123) }}/{{ tmedia(123, 'large') }}で解決する必要があります。マッピングがない場合は元の画像にフォールバックします。通常のmedia_url()はマップを無視します。 -
ブラウザーで確認する — 言語プレフィックス付き URL(
{site}/ms/<page-slug>/)にアクセスし、翻訳済みの文字列が表示されることを確認します。また、<head>にすべての言語の<link rel="alternate" hreflang="…">が含まれていること、canonical とog:urlに/ms/プレフィックスが付いていること、og:site_nameに翻訳済みのサイト名が表示されog:localeが言語と一致すること、languages()/lang_url()の切り替え用 URL にプレフィックスが付いていること、デフォルト言語にはプレフィックスが付かないことを確認します。
注意点
- プレーンテキストの翻訳。
wpcanai-i18n-set-translationsは値から HTML を取り除きます。マークアップはt()の中ではなく、テンプレート内のt()の周囲に記述してください。 - キーは完全一致です。 翻訳が適用されるのは、
t()のソースが文字単位で完全に一致する場合だけです。ソース文字列を渡し直す際に、トリミング、改行位置の変更、句読点の変更をしないでください。 - デフォルト言語は読み取り専用です。
wpcanai-i18n-set-translations/wpcanai-i18n-set-media-mapはデフォルト言語を拒否します。ソーステキストがデフォルトの表示内容です。 - インデックスが古い場合。
_canai_html/_canai_jsの編集後、一覧表示の前に再スキャンしてください。 - 設定するまで何も行われません。 デフォルト以外の言語が設定されていない場合、プレフィックス付きルーティング/リダイレクト/hreflang は無効になり、
t()/tmedia()は変更なしで値を返します。 - コンテンツのオーバーライドはフロントエンド専用です。 管理画面、REST の編集コンテキスト、デフォルト言語では常に元の値が表示されます。
/{lang}/のフロントエンド表示のみが切り替わります。 - 編集者は wp-admin でも翻訳できます。 プラグイン v1.70.0 以降、
post.php?post=<id>&action=edit&lang=<slug>(「言語モード」)で開いたブロックエディターの投稿は、その言語のオーバーライド用 blob(wpcanai-i18n-set-post-overridesが書き込むものと同じ_canai_i18n_<lang>データ)を読み込み、保存します。ユーザーが「エディターで」翻訳を編集したと言った場合は、未翻訳だと決めつけず、wpcanai-i18n-get-content { "post_id": <id>, "lang": "<slug>" }で読み戻してください。 - 検索で一致するのはデフォルト言語のテキストのみです — WP の検索はオーバーライド用 blob をインデックスしません。
Twig ヘルパー
t()、tmedia()、current_lang()、languages()、lang_url()、turl() — references/REFERENCE.md を参照してください(turl() は Media & Links の項にあります)。turl('/path/')(プラグイン v1.88.0)は現在の言語に対応する home_url() です。デフォルト言語では通常の URL が返され、ms では /ms/path/ が返されるため、内部リンクでプレフィックスが重複することはありません。turl(path, lang) は特定の言語を対象にします(切り替えの場合)。slug_url() も同様にローカライズされ、get_menu() の項目は title / description が翻訳され、url がローカライズされた状態で返されます。raw_title / raw_description には未翻訳のテキストが格納されます(各言語のメニューは記述されたとおりに表示されます)。current_language() と language_switcher() は引き続き current_lang() と languages() のエイリアスとして機能します(すでにこれらを使用しているテンプレート向けです)。新しいテンプレートではネイティブ名を使用してください。
よくあるワークフロー(汎用表記)
ツール名 + JSON 引数を使用し、ホストの MCP 呼び出し構文に合わせてください。
DevTools でスタイルを調整する(3 回の呼び出し)
ユーザーがブラウザーで試し、ページ URL、表示されているテキスト、プロパティ(例:「text conference、line-height を 1.15 に設定」)を渡してきます。ページ全体を読み取ったり、ローカルに複製したりせず、呼び出しは 3 回だけです。
- 投稿 ID を解決します。
wpcanai-list-pages {}を呼び出し、URL のスラッグ/タイトルを照合します(ホーム URL は静的フロントページです。タイトルが曖昧な場合は、wpcanai-read-settings { "keys": ["page_on_front"] }でpage_on_frontを読み取ります)。WooCommerce のルートの場合は、wpcanai-resolve-content-id { "type": "shop" }などを使います。 - 要素を見つけます。
wpcanai-grep-content { "post_id": <id>, "pattern": "conference", "max_length": 1000, "context_lines": 2 }→ 行のmatchが、要素のクラスを含むバイト単位で正確な行です。 - その要素内だけを編集します。
wpcanai-replace-in-meta { "post_id": <id>, "scope": { "text": "conference" }, "replacements": [{ "from": "leading-none", "to": "leading-[1.15]" }], "require_all": true }。 要素にすでにユーティリティがある場合は、任意の値を指定できる Tailwind ユーティリティ(leading-[1.15]、text-[17px]、tracking-[-0.01em])を優先します。class 属性がない場合は、同じスコープ内でfrom: "<h1"→to: "<h1 class=\"leading-[1.15]\""を使います。プロパティに対応するユーティリティがない場合に限り、field: "css"で CSS ルールを追加します。
ステップ 3 で replace_no_match が返された場合は、message(Nearest match: <kind> at line …)を確認します。whitespace_only の場合は、同じスコープ指定の呼び出しを ignore_whitespace: true を付けて再試行します。outside_scope の場合は、クラスが別の要素(通常は親要素)にあるため、その要素に含まれる scope.text を選びます。一致させるために scope を外してはいけません。そうすると別の要素が書き換えられます。対象がスコープ指定した要素で間違いない場合は、まず ignore_whitespace: true を試し、次にスコープを指定した grep-content(max_length: 1000)で正確なバイト列を確認します。scope.text には、要素自身の最初のテキストまたは属性値を指定します。サーバーはテキストの前にある最も近い開始タグをスコープにするため、子 <span> 内のテキストは見出しではなく span をスコープにします。単一プロパティの変更で、フィールド全体を read-meta してはいけません。その後に wpcanai-scan や Tailwind の再コンパイルは不要です(再実行するタイミングを参照)。
既存の HTML のセクションを編集または削除する
- ID を解決します —
wpcanai-list-pages{ }またはwpcanai-resolve-content-id{ "type": "shop" }などを使います。返されたcontent_post_id(または list-pages の行のid)を使用します。 - 読み取ります —
wpcanai-read-meta{ "post_id": <id>, "fields": ["html"] }(必要に応じて他のフィールドも追加します)。 - 対象を絞った置換を優先します。
grep-content(post_id、max_length: 1000)で取得したバイト単位で正確な行を基準に{from, to}の組を作成し、require_all: trueを指定してwpcanai-replace-in-metaを呼び出します。組が多い場合は、最初にdry_run: trueを追加します。ソースで属性が複数行にまたがっている場合は、ignore_whitespace: trueを使用します。 - 構造を書き換える場合に限り、全体を書き込む方法に切り替えます —
wpcanai-read-meta{ "post_id": <id>, "fields": ["html"] }(または一部の範囲:{ "post_id": <id>, "fields": ["html"], "lines": [from, to] })で読み取り、編集した後、expected_hashを指定してwpcanai-write-meta{ "post_id": <id>, "html": "<full updated HTML>" }を呼び出します。
既存ページの壊れたアセット URL を修正する
公開中のページが誤ったアセット URL を参照している場合(インポート時に残った相対パスや、移転した CDN など)、ドキュメント全体を書き直さずに修正します。
- ID を解決する —
wpcanai-list-pages/wpcanai-resolve-content-id→ ページ/テンプレートのpost_id。 - 公開 URL をメディアライブラリに取り込む — 不足しているアセットごとに、ホットリンク可能な URL は
wpcanai-sideload-urlを使います。ローカルのバイナリファイルは、sideload REST エンドポイント(POST {site}/wp-json/wpcanai/v1/sideload。許可されているcurlはこれだけです。「メディアのアップロード」を参照)を使います。返されたsource_urlをそれぞれ記録します。 { <old/broken reference exactly as it appears> : <new source_url> }の形式で、置換元から置換先へのマップを作成します。HTML に現れる各バリエーション(./img/x.png、img/x.png、/img/x.png)を含めます。- 適用する —
wpcanai-replace-in-meta{ "post_id": <id>, "field": "html", "replacements": [{ "from": "...", "to": "..." }, ...], "require_all": true }。影響を受けるフィールド/ページごとに 1 回呼び出します。それぞれのcountを確認し(require_allにより、一致しなかったfromがあればフラグが立ちます)、必要に応じて"field": "css"/"js"でも繰り返します。
新しいテンプレートを作成する
wpcanai-create-template{ "title": "...", "type": "component", "html": "...", "css": "..." }- レイアウトが必要な場合:
wpcanai-write-meta{ "post_id": <new_id>, "layout": <layout_post_id> }
設定を診断する
wpcanai-scan{ }— 委譲、レイアウト、テンプレート、構造ナビゲーション、コンテンツ漏えいの問題(missing_structure_comment/invalid_structure_comment/leaky_comment/leaky_secret)を検出します。wpcanai-manage-tools { "action": "list" }— 非表示のものも含むすべてのツール、それぞれが非表示になっている理由、および公開対象セットのトークン予算を確認できます。wpcanai-diagnosticsのtoolsとlanguagesグループでも同じ情報を要約して確認できます。
コメント/シークレットのセキュリティ監査
一括インポートの後、サイトをユーザーに引き渡す前、またはソース表示からの漏えいを監査するようユーザーに求められたときに実行します。sideload の事前処理と同じ定型手順です。
wpcanai-scan{ }— 構造/コメント/シークレットに関する検出結果をすべて収集します(post_idとfieldを記録します)。- 任意:サイト全体を grep する — スキャンで分類されない可能性のあるパターンを検索します。
wpcanai-grep-content { "pattern": "または、Twig にある疑わしい/* … */コメントを検索します。leaky_secretが検出された場合は、認証情報をメタデータから削除し、wp-config/環境変数/ブラウザーに表示されないサーバーサイドのスニペットに移します。 - 再スキャンする —
leaky_*の検出結果がなくなるまで繰り返します。検出結果が残っている間は、タスクが完了したと主張してはいけません。
本番環境向けに Tailwind をコンパイルする
実行するタイミング: ユーザーが /canai-mcp optimize production、/canai-mcp compile tailwindcss、compile tailwind、build css、tailwind build と指示した場合、または公開サイト用に Tailwind を事前コンパイルするよう求めた場合に実行します。テンプレートを編集するたびに自動実行してはいけません。これは明示的にオプトインする最適化手順です。
実行内容: デフォルトの Tailwind 配信方法では、Play CDN(プラグインの tailwind.min.js または cdn.tailwindcss.com)を使い、ページを読み込むたびに訪問者のブラウザーで JIT コンパイルします。このワークフローでは、エージェント側で CSS を事前コンパイルし、メタデータとして保存します。ビルド済み CSS が存在する場合、サーバーはその CSS をインラインで出力し、Play CDN スクリプトを読み込みません。訪問者には静的 CSS が配信され、コンパイル処理はエージェント側で行われます。
ビルド単位はレイアウトです。 レイアウトごとに CSS バンドルを1 つコンパイルします。レイアウトに加えて、そのレイアウトを通じてレンダリングされるすべてのページ/テンプレートをスキャンし、レイアウトの投稿に保存します。サーバーはレンダリング時にレイアウトのビルド済み CSS を取得し(そのレイアウトの投稿は、それを使用するすべてのページでレンダリングされます)、1 回だけ出力します。これにより、ビルド済み CSS が各ページに散在せず、CanAI Editor のレイアウトの Compiled Tailwind CSS パネルにまとめて保存されます。
ストレージの仕様
| メタキー | 保存場所 | 目的 |
|---|---|---|
_canai_tailwind_build | レイアウト投稿(wpcanai_template、タイプ layout) | レイアウトとそのすべての利用ページ向けにコンパイルされた CSS です。AssetManager::output_assets_head がこれを <style id="wpcanai-tailwind-css"> として出力し、そのレイアウトを通じてレンダリングされるページでは Play CDN をスキップします。 |
_canai_tailwind_hash | 同じレイアウト投稿 | 任意。エージェント側でのみ使用します。 ビルドの生成に使用した入力の sha256 です。再コンパイルの前に比較し、変更がない場合はスキップします。古さの検出には必須ではありません。サーバーは _canai_tailwind_epoch を使って最新状態を追跡します(以下のサーバー側の最新状態管理を参照)。 |
_canai_tailwind_epoch | 同じレイアウト投稿 | 書き込み時に自動設定される、ビルドのコンパイル時点のソースエポックです。サーバーはこれをグローバルエポックと比較して、古い状態かどうかを判断します。手動で設定する必要はありません。 |
_canai_tailwind_built_at | 同じレイアウト投稿 | Unix タイムスタンプです。空でない tailwind_build が書き込まれると wpcanai-write-meta が自動設定します(パネルの「N 分前にビルド済み」の表示に使用されます)。手動で設定する必要はありません。 |
空または未設定の場合、サーバーは Play CDN にフォールバックします。重複出力防止: レンダリング対象にビルドを持つレイアウトがある場合、サーバーはレイアウトのビルドのみを出力し、ページごとの _canai_tailwind_build は無視します。そのため、以前のページ単位のモデルでページに残された古いビルドが二重に出力されることはありません。wp-admin での手動編集も引き続き機能しますが、次回のコンパイルまでは実行時の CDN が使用されます。
サーバー側の最新状態管理(自動)。 tailwind_build が書き込まれるたびに、サーバーはビルドに現在のグローバルなソースエポック(_canai_tailwind_epoch)を記録します。また、テンプレートソース(_canai_html/css/js)または Tailwind 設定が変更されたとき、ブロックページの本文が変更されたとき(所有者による Gutenberg の保存、または MCP の書き込み)、あるいはページのフォーマットマークが変更されたときには、エポックを更新します。レンダリング時に、記録されたエポックが現在のエポックより古いビルドは古い状態として扱われ、古い CSS を出力する代わりに、ページは Play CDN にフォールバックします(正しい表示が保たれますが、処理は遅くなります)。そのため、再コンパイル前であっても編集後にページのスタイルが失われることはありません。これが、以下の tailwind_hash が現在は任意である理由です。正確性はもはやこれに依存しません。診断ページとレイアウトのコンパイル済み Tailwind CSSパネルには、古いビルドが表示されます。テンプレートを編集した後は、該当するレイアウトを再コンパイルしてインライン配信に戻してください。
ワークフロー
-
Tailwind 設定を読み取って、プラグインのセットを取得します。
wpcanai-read-settings { "keys": ["wpcanai_tailwind_settings"] }コンパイラーの呼び出し時には、返された
plugins配列(例:["forms", "container-queries"])を使用します。load_tailwindがnoの場合は処理を停止し、先に有効化するようユーザーに伝えてください(コンパイル対象の Tailwind がありません)。 -
レイアウトを列挙します —
wpcanai-list-templates {}を実行し、typeがlayoutの行を残します。各レイアウトがコンパイル対象です。 -
各レイアウトの利用ページを特定します — 有効なレイアウトがこのレイアウトになっているすべての投稿を対象とします。
wpcanai-list-pages {}とwpcanai-list-templates {}の行のうち、layout_idがこのレイアウトの ID と一致するもの。- WC デリゲートの本文:
wpcanai-resolve-content-id { "type": "shop" }(およびcart、checkout、my-account、product-category)を実行し、このレイアウトに解決される_canai_layoutを持つcontent_post_idを取得します。 - このレイアウトが
wpcanai_default_layoutの場合、明示的な_canai_layoutが設定されていない投稿も含めます(このレイアウトにフォールバックします)。 formatがblocksの行(wpcanai-list-pagesに含まれます)も利用ページです。本文は_canai_htmlではなくpost_contentであり、Twig の本文と同様にスキャンされます(プラグイン v1.67.0 以降。それ以前は、サーバーがブロックページで Play CDN を強制的に使用していました)。
-
ユニオンコンテンツを構築する — 1つの文字列に連結します。レイアウト自体の
_canai_html、すべてのコンシューマーの_canai_html、{% include 'slug' %}/{{ wpcanai_template('slug') }}で参照されるすべてのパーシャル(ヘッダー/フッター — 各スラッグから投稿 ID を特定し、その_canai_htmlを読み込みます)、さらに、formatがblocksの各コンシューマーについて、wpcanai-read-meta { "post_id": <id>, "fields": ["blocks"] }から取得した未加工のブロックマークアップ(classNameの値はブロックコメントの JSON とレンダリング後のclass=""の両方に含まれるため、未加工のマークアップがスキャン対象として適切です)。blocks ページのcssスロットはユニオンに含めないでください — これは Tailwind のソースではなく、加工されずに出力される通常の CSS なので、スキャン対象のユーティリティクラスには影響しません。また、ページ上でcssのみを書き込んでもソースエポックは更新されないため、ステップ 5 でこれをハッシュ化すると、ドキュメント化された入力が変更されていてもビルドが「最新」と判定されてしまいます。レイアウト内のあらゆる場所で実際に使われているクラスを Tailwind スキャナーが検出できるよう、一時的な.htmlファイルに書き込みます。 -
入力をハッシュ化する —
union_content + "\n--\n" + plugins.sort().join(",") + "\n--\n" + tailwind_versionの sha256 を計算します。レイアウトに既存の_canai_tailwind_hashがある場合は比較します。一致したら、そのレイアウトをスキップし、「スキップ(最新の状態)」としてカウントします。マシン間でハッシュが安定し(誤って v4 でビルドした場合も衝突せず無効化される)ように、tailwind_versionには実際にコンパイルで使用する v3 のバージョンを指定してください。ハッシュ化にはPython ではなく Node を使用します(ローカルスクリプト用の接続処理を参照)— 例:node -e "const c=require('crypto'),fs=require('fs');console.log(c.createHash('sha256').update(fs.readFileSync(process.argv[1])).digest('hex'))" hash-input.txt。 -
Tailwind v3 でローカルコンパイルする(サーバーではコンパイルしません)。v4 ではなく Tailwind v3 を使用してください。実行時の配信には Tailwind v3 Play CDN を使用します。プラグイン v1.58.2 以降、これはデフォルトで
assets/lib/tailwind/内のプリビルドバンドルを意味します(Resource Source= Internal)。サイト所有者がソースを外部に切り替えた場合のみ、cdn.tailwindcss.comが使われます。いずれの場合も v3 なので、プリコンパイラーも一致させるために必ず v3 を使用してください。どちらのランナーもnpm run buildなしで動作します。npx tailwindcss@^3 -i input.css -o /dev/stdout --content "<temp.html>"。npx @tailwindcss/cliは使用しないでください — このパッケージは Tailwind v4 であり、ビルドが壊れます(以下の警告を参照)。- v3 リリースの Tailwind スタンドアロンバイナリ(例:
v3.4.xタグのtailwindcss-macos-arm64— Node 不要の単一実行ファイル)。明示的に v3 を固定してください。「latest」のバイナリは v4 です。input.cssは@tailwind base; @tailwind components; @tailwind utilities;です。ステップ 1 のプラグインは、一時的なtailwind.config.js(plugins: [require('@tailwindcss/forms'), ...])で有効にします。レイアウトごとにビルドするため、Preflight/base はページごとではなく一度だけコンパイルされます。
⚠ v3 を使用してください。
@tailwindcss/cliは絶対に使用しないでください。 Tailwind v4 では、この手順でビルドすると警告なしにモバイル専用ビルドが生成されます。v4 は--contentとtailwind.config.jsの両方を無視し、従来の@tailwind base/components/utilitiesディレクティブでは v4 のデフォルトテーマが読み込まれません。そのため、テーマトークンを必要とするユーティリティがすべて除外されます(--breakpoint-*→ レスポンシブなmd:/lg:バリアントなし、--spacing→p-2なし、フォントサイズ →text-smなし)。flex/hiddenのような、テーマに依存しない静的ユーティリティだけが残ります。Tailwind v3 では、@tailwindディレクティブ、tailwind.config.js、--contentが正しく機能します。 -
ビルドを検証してから、レイアウトに保存する。書き込む前に、コンパイルした CSS を簡易チェックしてください。サイズが十分にあり、少なくとも1つの
@media (min-width:ルールを含んでいる必要があります(つまり、レスポンシブユーティリティが出力されている必要があります)。満たさない場合 — v4 でコンパイルしたときに典型的に見られる症状です — ビルドは壊れています(モバイル専用)。保存せず、レイアウトを失敗としてカウントし、動作中の Play CDN フォールバックをそのまま残してください(_canai_tailwind_buildが空または存在しない場合、サーバーは CDN を引き続き配信します)。検証に合格したら、wpcanai-write-metaで書き込みます。wpcanai-write-meta { "post_id": <layout_id>, "tailwind_build": "<full compiled CSS>", "tailwind_hash": "<sha256>" }その後、古いページごとのビルドをまだ保持しているコンシューマーでは、古いページごとのコンパイルによるものを削除します。
wpcanai-write-meta { "post_id": <consumer_id>, "tailwind_build": "", "tailwind_hash": "" }。重複排除ガードはすでにこれらを無視しますが、削除しておくことでデータの整合性が保たれ、パネルにも正確な情報が表示されます。これらのフィールドを永続化するのはwpcanai-write-metaのみです。他の書き込み方法は使用しないでください。 -
報告 —
X layouts compiled, Y skipped (already current), Z failedに加え、削除したコンシューマーのページごとのビルド数を報告します。失敗した場合は、レイアウト ID と理由を列挙します。
結果の確認
ブラウザーでフロントエンドのページを表示します。<head> に <style id="wpcanai-tailwind-css">…</style> が含まれ、<script src=".../tailwind.min.js"> は含まれていないことを確認します。Play CDN スクリプトがまだ表示される場合、ページのレイアウトに空の _canai_tailwind_build が設定されています(手順 7 で正しいレイアウト ID に書き込んだか再確認してください)。または、ページがコンパイルしたものとは別のレイアウトを使用しているか、load_tailwind が no になっています。
コンパイル済みレイアウトでレンダリングされたブロックページには、同じ <style id="wpcanai-tailwind-css"> が表示され、tailwind.min.js は含まれません。Twig の兄弟ページでは CDN が読み込まれないのに、ブロックページで読み込まれる場合は、ビルドが古くなっています。ブロックページの本文は Gutenberg で保存するたびに変更されるためです(再実行するタイミングを参照)。
再実行するタイミング
レイアウトのビルドへの入力が変更されたときは、いつでも再実行してください。対象には、レイアウト自体の _canai_html(インラインの tailwind.config = {…} ブロックも含みます。新しいトークンは、サーバーが Play CDN をスキップするため、コンパイル後は実行時に認識されません)、コンシューマーのページ/テンプレートの _canai_html、ブロックページの本文(所有者による Gutenberg での保存、または wpcanai-write-page)、ページの形式マークの変更、共有パーシャル(ヘッダー/フッター)、_canai_layout の割り当て、wpcanai_tailwind_settings のプラグインセットが含まれます。レイアウト単位のトレードオフに注意してください。**コンシューマーを1つ編集するだけで、レイアウト全体のビルドが古くなります。**手順 5 のハッシュチェックにより、「毎回再実行」しても低コストです。実際に変更があったレイアウトのみ再コンパイルされます。
**部分的な編集だけなら、再コンパイルは必須ではありません。**サーバーは各レイアウトのビルドに鮮度エポックを付与し、レンダリング時にソースに対して古くなったビルドを破棄して、Play CDN にフォールバックします(AssetManager::output_assets_head)。したがって、replace-in-meta の後もページは正しくレンダリングされ、新しい leading-[1.15] などのユーティリティは実行時 CDN から提供されます。コストは、次に意図的にコンパイルするまでページで CDN が読み込まれることだけです。コンテンツを少し調整するたびにではなく、本番環境向けの最適化をユーザーが求めたときに再コンパイルしてください。
コンパイル後の実行時の動作
レンダリングされたページのレイアウトに空でない _canai_tailwind_build がある場合、AssetManager::output_assets_head はそのビルドのみ(重複排除ガードを参照)に加えて、1行のシム <script id="wpcanai-tailwind-shim">window.tailwind=window.tailwind||{config:{}};</script> を出力します。このシムにより、レイアウトのインライン tailwind.config = { ... }({{ wp_head() }} の後)が TypeError を発生させず、安全にプロパティへ値を書き込めます。その結果、コンパイル後はこのブロックに視覚的な効果はありません。すべてのテーマトークンを、コンパイラーに渡す一時的な tailwind.config.js に含める必要があります。レイアウト投稿には _canai_css/_canai_js がなくてもビルド取得用のキューに追加されるため、ビルドのみを保持するレイアウトも正しく出力されます。
制限事項/注意点
- レイアウトごとのユニオンサイズ。 レイアウトのビルドには、そのレイアウトを使うすべてのページで使用されるクラスが含まれるため、各ページに、ページごとに完全にビルドした場合より多くの CSS が含まれます。その代わり、シェル(ヘッダー/フッター/レイアウト)と Preflight を重複排除でき、CSS も 1 か所で確認できます。一般的なサイトであれば問題ありませんが、1 つのレイアウトがコンテンツの多様な大量のページに適用され、CSS のサイズが懸念になる場合は、それらのページを別のレイアウトに分けてください。
- 再ビルドとの結び付き。 ビルドはレイアウト単位なので、コンシューマーを 1 つ編集するだけで、レイアウト全体のビルドが無効になります。ハッシュによるスキップで再コンパイルのコストは抑えられますが、ほとんどのコンテンツ編集後にレイアウトが再コンパイルされることを想定してください。
- ページ単位ビルドからの移行。 既存のインストールでは、ページ上にビルドがあります。最初のレイアウト単位の再コンパイルが行われるまでは、重複排除ガードによって正しく処理されます(レイアウトのビルドがあればそれが優先され、なければページ単位のビルドが引き続き出力されます)。手順 7 のクリア処理で、順次削除されます。
- 任意の値。
class="text-[#abc123]"は動作します(Tailwind JIT はリテラル文字列をスキャンします)。値が Twig ソース内のリテラルであり、レンダリング時に構築されるものではないことを確認してください。class="text-{{ color }}"は検出されません。これは、どの Tailwind ビルドでも同じ制約です。 - レイアウト内のカスタム
tailwind.config = {…}。 一時的なtailwind.config.jsにも反映してください。そうしないと、コンパイル結果にそのトークンが含まれません。抽出は脆弱です。インラインブロックは JSON ではなく JS オブジェクトリテラルです(末尾のカンマ、シングルクォート、引用符のないキー、関数値、コメントが含まれる場合があります)。ローカルスクリプトの連携を参照し、Python ではなく Node で評価してください。一時的なtailwind.config.jsにmodule.exports = { ... }を書き込み、コンパイラーにrequire()させます。これにより、オブジェクトリテラルはそれを記述したものと同じエンジンで解析されます。有効な設定を抽出できない場合は、トークンが欠けたビルドを黙って出荷せず、明示的にエラーにしてください。
HTML 操作のガイダンス
- テンプレートでは、セクションの境界を示すナビゲーションコメントに
**{# Type / Short Label #}** を使用します。これらのラベルを使って境界を見つけ、実装メモの{# @dev … #}は無視してください(コメントのルールについては REFERENCE.md を参照)。 - ブロックを削除する: 開始位置の Twig コメント(または判別可能な開始位置)から、そのセクションの末尾(次の兄弟セクションのコメント、閉じる構造タグ、または include 行)までを削除します。
- ブロックを編集する: そのセクション内のマークアップだけを置き換え、文字列の残りの部分は変更しないでください。
- 最終的な文字列はエージェント内で構築し、
**wpcanai-write-meta**に渡してください。外部スクリプトは不要です。
履歴/元に戻す(スナップショット)
CanAI のコンテンツを書き込むたびに、反映前の状態を専用テーブル(postmeta ではありません)にスナップショットとして保存します。これが元に戻すための手段です。以前の _canai_html を手作業で再構築しようとせず、書き込みに問題が起きたらすぐに利用してください。スナップショットを操作する管理画面はありません。これらのツールだけが利用可能です。
保存される内容。 対象となるメタキーは、次の 8 つだけです。_canai_html、_canai_css、_canai_js、_canai_layout、_canai_delegate_page_id、_canai_context、_canai_context_mode、_canai_format。それ以外は保存されません。post_title、post_content、添付ファイルも対象外です。また、ページのスラッグ、ステータス、親ページ、順序も対象外です。wpcanai-update-page はスナップショットを作成せず、レスポンス内の previous が元に戻すための情報です。
整合性のないスナップショットを復元すると、整合性のない状態が再現されます。 たとえば、ページが blocks とマークされている一方で、空ではない _canai_html(変換の中断や別の書き込み元によって残された古い Twig 本文)を保持しているときに取得したスナップショットを復元すると、両方の値がそのまま戻ります。ページは引き続きブロックエディターで開きますが、フロントエンドではブロックではなく古い Twig が表示されます。フロントエンドが post_content にフォールバックするのは、_canai_html が空の場合のみだからです。
取得されるタイミング。 wpcanai-write-meta、wpcanai-write-page(ブロックへの変換パスのみ。操作は mcp-write-page-convert)、wpcanai-replace-in-meta、wpcanai-create-template、wpcanai-create-page、wpcanai-setup、wpcanai-import、プリセットのインストール/アンインストール、コンテンツを書き換えるメディアの更新、および wp-admin エディターからのすべての保存時に、書き込み前のスナップショットが自動的に取得されます。通常の書き込みで「スナップショットを取得する」ツールを呼び出す必要はありません。明示的に操作する唯一のケースは、以下の wpcanai-pin-current です。
保持期間。 投稿ごとに、ピン留めされていないスナップショットを10 件までリングバッファーで保持します。11 回目の書き込みで最も古いスナップショットが削除されます。ピン留めされたスナップショットは削除対象外で、投稿ごとに最大 10 件までです。
操作。 1 回の論理的な書き込みの一部として取得されたスナップショットには、共通の operation_id が付与されます(例:14 件の投稿に適用されるプリセットのインストール)。14 件のスナップショットを 1 件ずつ復元するのではなく、wpcanai-restore-operation を使って全体をロールバックしてください。
キルスイッチ。 すべての wpcanai/* アビリティと同様に、これらのツールはそれぞれ、サイト所有者が CanAI → AI Client → Tools で無効にできます。無効化されたツールは、ツール一覧に表示されなくなります。
wpcanai-list-snapshots
- 引数:
{ "post_id": int, "limit"?: int }—post_idは必須です。limitのデフォルトは 50 で、1~200 に制限されます。 - 戻り値:
{ "snapshots": [{ "id": int, "post_id": int, "operation_id": string, "operation_type": string, "actor": string, "created_at": string, "pinned": bool, "label": string|null, "bytes": int }] }— 新しい順です。メタデータのみが返されます。ペイロードは意図的に除外されています。「どれを使うか」という質問に答えるために、約 7 KB の行を 10 件読み込んでコンテキストを消費することを避けるためです。 - エラー: 呼び出し元がその投稿に対する
edit_post権限を持たない場合はforbidden。
wpcanai-get-snapshot
- 引数:
{ "snapshot_id": int }。 - 戻り値: 同じ要約フィールドに
"payload"が追加されます。これは、取得された{ "_canai_html": …, "_canai_css": …, … }マップです。nullは「メタ行が存在しなかった」ことを示します。差分を確認する必要がある場合は、復元前にこれを読み取ってください。 - エラー:
wpcanai_snapshot_not_found、forbidden。
wpcanai-restore-snapshot
- 引数:
{ "snapshot_id": int }。 - 戻り値:
{ "success": true, "post_id": int }。 - 現在の状態が先に取得されるため、復元操作自体も元に戻せます。誤ったスナップショットを復元しても致命的な問題にはならず、復旧できます。
- エラー:
wpcanai_snapshot_not_found、forbidden、forbidden_unfiltered_html— 復元では未加工の HTML/JS を投稿に書き戻すため、元の書き込みと同様にunfiltered_htmlが必要です(API キーを使う呼び出し元はこの条件を満たしますが、Cookie 認証の非管理者は満たさない場合があります)。
wpcanai-list-operations
- 引数:
{ "limit"?: int }— デフォルトは 20 で、1~100 の範囲に制限されます。 - 戻り値:
{ "operations": [{ "operation_id": string, "operation_type": string, "actor": string, "created_at": string, "posts": int }] }— 新しい順で、サイト全体が対象です(投稿ごとではありません)。postsは、その操作の対象となった投稿数です。
wpcanai-restore-operation
- 引数:
{ "operation_id": string }。 - 戻り値:
{ "success": bool, "restored": int, "failed": int, "post_ids": int[] }。 successはfailed === 0を意味し、restored > 0ではありません。 15 件中 14 件をロールバックした場合はsuccess: falseが返されます。restoredが 0 以外でも「完了」と見なさないでください。部分的な状態をユーザーに報告してください。- 書き込みを始める前に、影響を受けるすべての投稿の権限を確認します。途中で止まるロールバックは、開始しない場合よりも事態を悪化させます。
- エラー:
wpcanai_operation_not_found、forbidden(編集できない投稿の名前を示します)、forbidden_unfiltered_html。
wpcanai-pin-snapshot
- 引数:
{ "snapshot_id": int, "pinned": bool, "label"?: string }—snapshot_idとpinnedは必須です。labelは任意で、ピン留め時のみ意味があります。 - 戻り値:
{ "success": true, "snapshot_id": int, "pinned": bool }。 - ピン留めすると、スナップショットがリングバッファによる削除の対象外になります(上限:投稿ごとに 10 件)。ピン留め解除は常に可能です。
- エラー:
wpcanai_snapshot_not_found、forbidden、wpcanai_snapshot_pin_failed。
wpcanai-pin-current
- 引数:
{ "post_id": int, "label": string }— 両方とも必須です。labelは空でない 191 文字以内の文字列にしてください(例:"fix broken product page — verified in browser")。 - 戻り値:
{ "success": true, "snapshot_id": int, "pinned": true, "label": string, "created_at": string, "reused_existing": bool }。 - ブラウザーで変更を検証した後に、このツールを呼び出してください。 スナップショットは通常、書き込み前にのみ取得されるため、動作を確認したばかりの状態をピン留めできる行はありません。誰かが再び投稿を編集するまで行は作成されず、その時点では確認済みの状態は以前の状態となり、すでに削除されている可能性があります。
- 現在のコンテンツが最新のスナップショットと一致している場合は、重複を書き込まず、そのスナップショットをピン留めします(
reused_existing: true)。 - エラー:
wpcanai_invalid_label(未指定または 191 文字超過)、wpcanai_post_not_found、wpcanai_not_canai_post(投稿に CanAI コンテンツが含まれていません。ピン留めすると「この投稿には何もなかった」という状態が検証済みとして記録されるためです)、forbidden、およびピン留め数が 10 件に達している場合の上限エラー。まずwpcanai-pin-snapshotでピン留めを解除してください。
復旧ワークフロー
wpcanai-list-snapshots { "post_id": 123 }→ 問題のある書き込みより前の行を探します(created_at/operation_typeを確認してください)。- 任意:
wpcanai-get-snapshot { "snapshot_id": 456 }→ ペイロードが復元したいコンテンツであることを確認します。 wpcanai-restore-snapshot { "snapshot_id": 456 }。- ブラウザーでページを確認します。
wpcanai-pin-current { "post_id": 123, "label": "known-good after rollback" }を呼び出し、復元した状態が削除されないようにします。
複数の投稿に損害が及んでいる場合(プリセットのインストールまたはインポートの失敗など)は、すぐに
wpcanai-list-operations → wpcanai-restore-operation を実行してください。
アクションルーター(クイックリファレンス)
| 目的 | ツール |
|---|---|
| テンプレートを一覧表示する | wpcanai-list-templates |
CanAI ページを一覧表示する(下書きを含むすべてのページ:all_pages: true) | wpcanai-list-pages |
| フィールドを読み取る | wpcanai-read-meta |
| フィールドを書き込む | wpcanai-write-meta |
| 新しいテンプレート投稿を作成する | wpcanai-create-template |
| 新しいページを作成する(CanAI メタ付き) | wpcanai-create-page |
| ページの名前変更、スラッグ変更、公開、移動を行う(形式を問わない) | wpcanai-update-page |
| 2 つのメニュー(プライマリ、フッター)を読み取る | wpcanai-get-menus |
| メニューリンクを設定または変更する | wpcanai-write-menu(Menusを参照) |
| ロケーションまたは言語を既存のメニューに割り当てる、または割り当てを解除する | wpcanai-assign-menu |
| WP/WC/CanAI オプションを読み取る | wpcanai-read-settings |
| WP/WC/CanAI オプションを更新する | wpcanai-update-settings |
| 任意の wp_option を読み取る(許可リスト) | wpcanai-get-option |
| 任意の wp_options を更新する(許可リスト/承認) | wpcanai-update-options |
| 保留中のオプション更新を確認する | wpcanai-get-pending |
| 推奨サイトのブートストラップを行う | wpcanai-setup |
| タイプに対応する投稿 ID を確認する | wpcanai-resolve-content-id |
| WC ページ ID | wpcanai-get-wc-page-ids |
| 診断する | wpcanai-scan |
_canai_* メタを grep する | wpcanai-grep-content |
| 環境/ネットワークを診断する | wpcanai-diagnostics |
ページキャッシュを消去する(書き込み時の purged で対象にならなかった場合) | wpcanai-purge-cache |
| コンテンツなしのインベントリ+ハッシュ | wpcanai-export { "summary": true } / wpcanai-read-meta { "hash_only": true } |
| プリセットを一覧表示/インストール/削除する | wpcanai-list-presets / wpcanai-install-preset(⚠ clean_slate) / wpcanai-uninstall-preset |
| CanAI コンテンツをエクスポート/インポートする | wpcanai-export / wpcanai-import |
| 不適切な書き込みを元に戻す(1 件の投稿) | wpcanai-list-snapshots → wpcanai-restore-snapshot |
| 操作全体を元に戻す(複数の投稿) | wpcanai-list-operations → wpcanai-restore-operation |
| 1 件のスナップショットのペイロードを読み取る | wpcanai-get-snapshot |
| 検証済みコンテンツのチェックポイントを作成する | wpcanai-pin-current(ピン留め/解除:wpcanai-pin-snapshot) |
FluentSnippets(オプトイン)、wpcanai-replace-in-snippet を含む | canai-yolo スキル — ここでは説明していません |
| 本番環境用に Tailwind を事前コンパイルする | wpcanai-write-meta と tailwind_build + tailwind_hash を使用(Compile Tailwind for Productionを参照) |
| サイトを翻訳する(ネイティブ i18n) | Native string translation ワークフローを参照 |
| ネイティブ i18n 言語を読み取る/設定する | wpcanai-i18n-get-settings / wpcanai-i18n-set-settings |
翻訳可能な文字列を一覧表示する(1 ページ:post_id) | wpcanai-i18n-list-strings |
| 翻訳を書き込む(一括) | wpcanai-i18n-set-translations |
言語ごとの画像(tmedia) | wpcanai-i18n-get-media-map / wpcanai-i18n-set-media-map |
| 文字列インデックスを再構築する | wpcanai-i18n-rescan |
| 投稿コンテンツのオーバーライド(CPT/長文形式) | wpcanai-i18n-get-post-overrides / wpcanai-i18n-set-post-overrides |
| ターム名/説明のオーバーライド | wpcanai-i18n-get-term-overrides / wpcanai-i18n-set-term-overrides |
| コンテンツ翻訳の作業キュー | wpcanai-i18n-list-content |
| 翻訳する投稿のソースを読み取る | wpcanai-i18n-get-content |
| サイト名/キャッチフレーズ/アーカイブ SEO(グローバル文字列) | wpcanai-i18n-get-global-strings / wpcanai-i18n-set-global-strings |
セキュリティ
- API キーはパスワードと同様に扱い、使用しない場合は AI Client → Connections で無効化してください。
- ローカル以外のサイトでは HTTPS を優先してください。