
WordPress サイトに AI チャットを組み込むと、モデルとベクトルインデックスに渡すテキストをどこから取るかによって、会員限定の内容が未ログインの訪問者への回答に漏れるかどうかが決まります。AI Chat for Amazon Bedrock の固定コミット 628d350 では、includes/class-ai-chat-bedrock-content.php がこれを 1 つの出口にまとめています。記事全体が公開かどうかを確かめ、表示ルール付きのブロックを取り除き、未ログインの訪問者として本文を描画し、その描画結果だけを使います。本記事ではこのソースとリポジトリ付属の合成データによるテストをもとに、各処理が何を担うか、noindex ページを別扱いにする理由、そしてサイト側で補う必要がある部分を説明します。
プラグイン全体については AI Agents & Chat for Amazon Bedrock:本サイトで使っている WordPress 用チャット・MCP プラグイン、同じプラグインの注文データに関する別の境界については 「荷物」「出荷」「物流」だけでは足りない:WooCommerce のチャットアシスタントは注文の質問をどう見分けるか を参照してください。以下の結論はソースとテストファイルを読んで得たものです([O]、プロジェクト自身の実装とアサーション)。本記事ではテストを実行しておらず、実際のサイトでの検証もしていません。
タグを取り除くだけでは足りない理由
ファイル冒頭のコメントが経緯を説明しています。会員・表示制御プラグイン(コメントには Block Visibility、Paid Memberships Pro、MemberPress、Restrict Content などが挙がっています)はページの描画時に一部のセクションを隠すため、データベースに保存された post_content には訪問者に見えない文章が残っています。保存済みのマークアップからタグを取り除いてインデックス化した結果、会員限定の段落が埋め込みに入り、訪問者の質問に答えるときの参考資料にも入りました。コメントによれば、プラグインがモデルやベクトルインデックスに渡すものはすべてこのクラスから取得されます。誰もログインしていない状態で記事を the_content に通し、その出力だけを使います。
外部からの入口は public_text() です。未ログインの訪問者に見えるプレーンテキストを、タイトルを先頭にし、後でパッセージに分割できるよう段落の区切りを保ったまま返します。
記事全体の判定:公開か、回答に使えるか
is_public() は、記事のステータスが publish で、閲覧パスワードがなく、投稿タイプが公開閲覧可能(is_post_type_viewable())であることを求めます。条件を満たさない記事では public_text() は空文字列を返します。サイトはフィルター ai_chat_bedrock_is_public_post で、公開済みの記事を非公開と判定させることができます。コメントの例は、会員プラグインがリクエストごとに保護する会員専用の投稿タイプです。記事全体が限られた読者向けの内容は、この段階で除外します。
チャットとエージェントには、もう 1 つ is_answerable() の判定があります。公開記事であっても、SEO プラグインで noindex とされたページは既定では回答に使われません。コメントの理由は、サイトが検索エンジンから外しているページには通常理由がある、というものです。たとえばフォームで配布するダウンロードが載ったサンクスページ、キャンペーンのランディングページ、特定の顧客 1 人向けのページです。チャットはサイト内検索の一種なので、設定項目 include_noindex をオンにしない限り、それらも同じく除外します。コードは Yoast SEO、Rank Math、SEOPress の記事単位と投稿タイプ既定の設定、および All in One SEO の記事単位の設定を読みます。「設定 → 表示設定」の「検索エンジンがサイトをインデックスしないようにする」は対象外です。ステージングサイトを隠すのに使われるためです。ほかの SEO プラグインは ai_chat_bedrock_post_is_noindex で接続できます。
2 つのことを区別してください。noindex は検索エンジンに対する編集上の希望であって、アクセス制御ではありません。noindex のページも公開されたままで、リンクを知っていれば誰でも開けます。コードのコメントにも、読み上げはこの判定の影響を受けない(訪問者はすでにそのページにいる)と書かれています。index_version() は抽出ロジックのバージョン(現在は VERSION = 3)と noindex ページを含めるかどうかを組み合わせてインデックスのバージョンとし、どちらかが変わるとすべての記事を処理し直します。
ブロックと描画:ルールがあれば削除し、訪問者として描画する
訪問者として描画するだけでは不十分です。コメントには実際に起きた例が書かれています。Block Visibility はフロントエンドのリクエストでしかフィルターを読み込みませんが、設定画面のインデックス作成もチャットの回答も admin-ajax を通るため、会員限定ブロックが全員向けに描画され、インデックスに入りました。そこで without_restricted_blocks() は、どのリクエストかに関係なく、描画の前に表示ルールを持つブロックをすべて削除します。そのルールが訪問者に効くかどうかを推測することはしません。未ログインの訪問者にだけ表示するブロック(「ログインして続きを読む」など)も一緒に削除されます。コメントの考え方は、ログインの案内を 1 つ失っても損はないが、どのルールでブロックが隠れるかの推測を誤れば内容が漏れうる、というものです。
テストファイル tests/content.php は、合成ブロックで blockVisibility 属性のいくつかの書き方を確認しています。そのアサーションを表にまとめます。
| ブロックの設定(テストフィクスチャ) | テキストに含まれるか |
|---|---|
有効な controlSets、ログインユーザーのみ表示のルール | 含まれない。公開グループの中に入れ子になった同種のブロックも削除 |
有効な controlSets、未ログインの訪問者のみ表示のルール | 含まれない |
hideBlock: true | 含まれない |
1.x 形式:visibilityByRole でロールを指定 | 含まれない |
有効な scheduling | 含まれない |
プラグインが知らない設定(フィクスチャでは somethingNew) | 含まれない。未知の設定はすべてルールとみなす |
無効または空のルールセット、visibilityByRole: all、hideBlock: false、無効な scheduling | 含まれる。これらの設定は誰も制限しない |
入れ子のブロックを削除するときは、親ブロックの innerContent にある対応するプレースホルダーも取り除き、親ブロック自身のマークアップは残します。削除するものがなければそのまま返します。ほかのプラグインの制限付きブロックは ai_chat_bedrock_block_is_restricted で宣言でき、テストでは className が paywall の段落でこれを確認しています。
続いて render_as_guest() が現在のユーザーを一時的に 0 にし、グローバルの $post を設定して、削減後の本文を the_content に通します。描画中はフィルターが直接 echo した出力を出力バッファで破棄し、finally で元のユーザーと元のグローバル記事を戻します。静的フラグにより、描画中にフィルターが再びテキストを求めても再帰しません。最後に to_text() が script、style、noscript、template、form、svg、iframe の要素を丸ごと取り除き(コメントによれば wp_strip_all_tags はフォームのラベル文字を残すため)、結果はフィルター ai_chat_bedrock_indexable_text を通ります。このフィルターのドキュメントには、さらに削るためにだけ使い、訪問者が読めない文章を加えてはならないと書かれています。
テストと読み上げ:同じ境界の 2 つの確認点
テストファイルの冒頭に実行方法が書かれています。以下のクローンとチェックアウトの手順は本記事で補ったもので、ソースには必要な PHP のバージョンが書かれていません。
git clone https://github.com/noteflowai/ai-chat-for-amazon-bedrock.git
cd ai-chat-for-amazon-bedrock
git checkout 628d350366fb120343dd7506f259c64267ae8025
php tests/content.php
すべてのアサーションが通ると OK: guest-visible content checks passed を出力し、失敗があると標準エラーに FAILED と失敗の一覧を出して終了コード 1 で終わります。テストは WordPress をブロックパーサーも含めてスタブ関数で置き換え、模擬の表示制御プラグインを登録します。ログインユーザーにはすべてが見え、訪問者には members-only のセクションが見えません。中心となるアサーションは、会員限定セクションにある合成の割引コード TIGER42 が訪問者向けテキストに現れないこと、その前後の公開段落が残ること、描画後にログインユーザー(ID 7)とグローバル記事が元に戻ることです。下書き、パスワード付きの記事、閲覧できない投稿タイプには公開テキストがありません。ブロックのフィクスチャは、公開の説明と会員グループを持つ講座ページを模したもので、本サイトの 講座 の解説ページにある「ログインして続きを読む」構成に近いものです。提示されたテストファイルには、noindex 判定を確認するアサーションはありません。
読み上げ機能は includes/class-ai-chat-bedrock-speech.php にあります。ファイル冒頭のコメントによれば既定でオフで、2 つの部分からなります。チャット回答の「聞く」ボタンはサイトが署名した回答テキストだけを読み上げます。記事の「この記事を聞く」は未ログインの訪問者が読めるテキストだけを Amazon Polly に送るため、会員限定の内容は送られず、音声は記事が変わるまでアップロードフォルダーに保存されます。同じファイルでは、記事の読み上げは既定で post タイプだけに提供され(フィルター ai_chat_bedrock_speech_post_types)、設定でログインした人だけが聞けるようにもできます。提示された読み上げのソースの抜粋は不完全で、本記事ではテキストの出口を呼び出す具体的なコードを確認していません。上記はコメントに基づいています。
制約と注意点
- 組み込みのブロック単位の識別は Block Visibility の属性だけを認識します。ショートコード、ページ全体のルール、ほかのブロック属性で内容を制限する会員プラグインは、訪問者としての描画時にそのフィルターが現在のリクエストで実際に読み込まれていることに頼るか、サイトが自分で
ai_chat_bedrock_block_is_restrictedやai_chat_bedrock_is_public_postのフィルターを書く必要があります。Block Visibility の例は、前者の前提が常には成り立たないことを示しています。導入後は実際のサイトで未ログインのまま読み戻して確認してください。会員限定ブロックにしか答えがない質問をし、回答にも引用されたパッセージにもそれが含まれないことを確かめます。 - テストはスタブ関数と合成データによる単体テストです。これらのフィクスチャでこのコードがどう動くかを示すもので、実際のサイトが安全であることも、すべての会員プラグインとの互換性も証明しません。
- 「削るだけで加えない」はフィルターのドキュメント上の約束であり、コードはフィルターが文章を加えることを止めません。サイトが書いたフィルターの責任はサイトにあります。
- テキストのキャッシュキーは記事 ID、更新日時、
VERSIONだけで構成されます。永続オブジェクトキャッシュがなければ現在のリクエスト内でのみ有効で、ある場合は最長 1 時間保持されます。記事を編集せずに会員プラグインの設定でルールを変えても、このキャッシュは無効になりません。それに応じてベクトルインデックスがいつ更新されるかは、本記事で読んだファイルの範囲外です。 - noindex ページの除外は、チャットとエージェントが何を材料にするかに影響するだけで、アクセス制御ではありません。保護が必要な内容は noindex ではなく、会員ルールや非公開の記事に置いてください。
- サイト上の Polly による読み上げと、本サイトの講座動画の AI ナレーションは別のものです。読み上げを有効にするには AWS の権限と従量課金も関わりますが、本記事ではその設定を扱わず、IAM や課金設定を変更する根拠にもなりません。
リンク
- includes/class-ai-chat-bedrock-content.php(固定コミット 628d350)
- tests/content.php(固定コミット 628d350、合成データ)
- includes/class-ai-chat-bedrock-speech.php(固定コミット 628d350)
- AI Agents & Chat for Amazon Bedrock:本サイトで使っている WordPress 用チャット・MCP プラグイン
- 「荷物」「出荷」「物流」だけでは足りない:WooCommerce のチャットアシスタントは注文の質問をどう見分けるか
- フィジカルAIラボ:すべての数字を確認できるフィジカルAI講座



