診断タブ — Test renderer / アクセスログ / Export Import / 互換性 / Bootstrap

プラグインの運用診断・デバッグ・移行・トラブルシューティングを担う最大ボリュームのタブです。5 つの独立した機能 (Test renderer / アクセスログ / 設定 export-import / 互換性チェック / md ホスト Bootstrap installer) が 1 タブに集約されています。

概要

「診断」タブは WordPress 管理画面 → LLMO Markdown → 診断 でアクセスできるタブです (URL: /wp-admin/admin.php?page=kashiwazaki-llmo-md&tab=diagnostics)。

本タブは他のタブと違い、設定値の保存だけでなく実行系のアクションを多く含みます。それぞれが独立したフォーム / nonce action を持ちます。

5 つの機能ブロック

# 機能 主な用途 関連ファイル
1 Test renderer (プレビュー) 任意 URL の md 化結果を管理画面で確認 (キャッシュ bypass) admin/settings-page-logic.php / includes/security.php
2 アクセスログ md ホストへのアクセス記録 (UA / status / latency) includes/security.php / {prefix}ksmd_access_logs table
3 設定の export / import JSON で設定をダウンロード / 復元 admin/settings-page-logic.php
4 互換性チェック PHP / WP / DOMDocument / mbstring / Object Cache / WPML / Polylang の動作要件確認 admin/sections/diagnostics.php
5 md ホスト Bootstrap installer md.example.com の DocumentRoot に index.php を生成 / 検証 / 削除 / 復元 includes/md-bootstrap-installer.php

画面構成

診断タブ Test renderer
図: タブ最上部の Test renderer。任意 URL を入力するとキャッシュを bypass して md 化結果をプレビュー (新規タブで)。
診断タブ アクセスログ設定
図: アクセスログ設定。有効化チェック、保持期間、IP 匿名化の 3 設定。
診断タブ 設定の export/import
図: 設定の export/import。JSON でのバックアップ取得とアップロード復元。
診断タブ 互換性チェック
図: 互換性チェック表。PHP / WP / DOMDocument / mbstring / Object Cache / WPML / Polylang を一覧。
互換性チェック表の拡大
図: 互換性チェック表の拡大。各行が「項目」「値」「判定 (✓ OK / ✗ NG)」の 3 列。
診断タブ md ホストブートストラップ
図: md ホストブートストラップ全景。WP 本体パス、md 側 DocumentRoot、index.php 状態カード、操作ボタン群。
bootstrap 操作の拡大
図: bootstrap 操作部分の拡大。状態再確認 / index.php を再生成 / 削除 / 直前の削除を元に戻す ボタン。
診断タブの 5 機能概念図
図: 診断タブの 5 機能を一望する概念図。

機能 1: Test renderer (プレビュー)

任意の URL を入力すると、その URL を md サブドメイン側で配信したらどう見えるかをこの管理画面内でプレビューします。キャッシュは bypass されるので、設定変更 / filter 修正の効果を即時確認できます。

使い方

1

「Test renderer (プレビュー)」セクションのテキスト入力に、確認したい URL を入力 (例: https://www.example.com/2026/04/30/hello-world/ 等)。空欄なら home_url('/') がデフォルト。

2

「プレビュー」ボタンをクリック。

3

新しいタブで md 化結果が表示される。Markdown インライン Schema.org ヘッダ、本文 Markdown、フッタが見える。

内部挙動

このフォームは admin-post.phpaction=ksmd_test_render へ POST 送信されます (target="_blank")。サーバ側では:

  1. nonce ksmd_test_render を verify (CSRF 防御)
  2. 入力 URL を esc_url_raw() でサニタイズ
  3. HMAC ベースのキャッシュ bypass token を生成 (cookieless)
  4. md ホスト側へ内部リクエスト実行 (実際にはサーバ内 WP_Query が走る)
  5. キャッシュキーを使わずに都度 regenerate
  6. 結果を Markdown のまま text/plain で出力

キャッシュ bypass token (HMAC)

本機能は cookieless で「これは管理画面からのテストリクエストですよ」という signed token を URL に乗せて識別します:

// includes/security.php (概念抜粋)
$token = ksmd_make_test_token( $url, $ts ); // HMAC-SHA256 ベース
$preview_url = add_query_arg(
    array( 'ksmd_preview' => 1, 'ksmd_t' => $token, 'ksmd_ts' => $ts ),
    $url
);

md-renderer 側で token が valid と判定された場合のみ cache_get / cache_set をスキップして強制 regenerate。

使うべき場面

機能 2: アクセスログ

md サブドメインへのすべてのリクエストを記録する機能です。AI クローラ (ChatGPT / Claude / Perplexity / Gemini) からのアクセスパターンを把握するのに有用です。

3 つの設定項目

項目 UI option key 用途
アクセスログを有効化 checkbox access_log_enabled (bool) 記録の ON/OFF
保持期間 select (1/7/30 日) access_log_retention_days (int) 古いログの自動切り捨て
IP 匿名化 checkbox access_log_anonymize_ip (bool) GDPR 対応の末尾オクテットマスク

記録される項目

1 リクエストにつき以下のフィールドが記録されます:

カラム 内容
logged_at DATETIME (UTC)
ip クライアント IP (IP 匿名化 ON 時はマスク済)
user_agent User-Agent ヘッダ (255 文字)
uri REQUEST_URI (500 文字)
status レスポンスステータス (200 / 404 / 503 等)
duration_ms サーバ処理時間 (ms)

専用テーブル {prefix}ksmd_access_logs

アクセスログは wp_options ではなく独立した 専用 MySQL テーブル に INSERT-only で書き込まれます。これにより wp_options のデシリアライズ競合が起きず、書き込みが O(1) で完結します。

CREATE TABLE {prefix}ksmd_access_logs (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    logged_at DATETIME NOT NULL,
    ip VARCHAR(64) NOT NULL DEFAULT '',
    user_agent VARCHAR(255) NOT NULL DEFAULT '',
    uri VARCHAR(500) NOT NULL DEFAULT '',
    status SMALLINT UNSIGNED NOT NULL DEFAULT 0,
    duration_ms INT UNSIGNED NOT NULL DEFAULT 0,
    PRIMARY KEY (id),
    KEY logged_at (logged_at)
);

テーブル作成は初回利用時または activation 時に dbDelta 経由で 1 回限り実行 (ksmd_access_log_table_ready option flag で重複防止)。

retention (保持期間) の働き

retention は読み込み時 (表示時) の WHERE 句で適用されます:

// includes/security.php
$cutoff = gmdate( 'Y-m-d H:i:s', time() - $retention * DAY_IN_SECONDS );
$wpdb->get_results( $wpdb->prepare(
    "SELECT ... FROM {$table} WHERE logged_at >= %s ORDER BY id DESC LIMIT %d",
    $cutoff, $limit
) );

つまり物理削除はされていない (TRUNCATE 時のみ削除)。retention を 1 日に短くしても古いログ行は DB に残るため、テーブルサイズ管理は手動 TRUNCATE で行ってください。

IP 匿名化 (GDPR 対応)

IP 匿名化を ON にすると、IPv4 / IPv6 別に末尾を 0 マスクします:

原 IP 匿名化後
192.168.1.42 192.168.1.0 (末尾オクテット 0)
2001:db8::1 2001:db8:: (下位 64 bit を 0 マスク)

IPv6 は inet_pton で 16 バイトに正規化したあと下位 8 バイトを 0 マスクし inet_ntop で文字列化します (RFC 7239 / GDPR 推奨の /64 anonymization)。

直近 50 件の表示

アクセスログ有効化中は、設定保存ボタンの下に直近 50 件のテーブルが表示されます (日時 / IP / UA / URI / Status / ms)。retention 範囲内のレコードのみ。

「アクセスログを全削除」ボタン

表の下部の赤いボタンを押すと、専用テーブルが TRUNCATE されます。 加えて旧バージョン互換のため delete_option('ksmd_access_logs') も実行されます。

機能 3: 設定の export / import

本プラグインのすべての設定を JSON ファイルとしてダウンロード / アップロード復元できます。

export の用途

JSON 構造の例

{
  "enabled": true,
  "kill_switch": false,
  "md_host": "md.example.com",
  "enabled_post_types": ["post", "page"],
  "enabled_routes": ["home", "archive", "category", "tag", "author", "search"],
  "enable_schema_header": true,
  "enable_schema_footer": true,
  "home_intro_markdown": "## About\n\n...",
  "schema_type_map": {
    "post": "Article",
    "page": "WebPage",
    "archive": "CollectionPage",
    "category": "CollectionPage",
    "tag": "CollectionPage",
    "author": "ProfilePage",
    "home": "WebSite",
    "search": "SearchResultsPage"
  },
  "cache_backend": "transient",
  "cache_duration": 3600,
  "default_in_language": "",
  "access_log_enabled": false,
  "access_log_retention_days": 7,
  "access_log_anonymize_ip": true
}

export の手順

1

「設定を JSON でダウンロード」ボタンをクリック

2

ブラウザにより ksmd-settings-{date}.json がダウンロードされる

import の手順

1

「JSON ファイルから復元」横の input でファイルを選択

2

ボタンをクリック → JSON が読み込まれて ksmd_settings option が更新

3

各タブを再読み込みすると新しい設定が反映されている

⚠️ Warning

import は現在の設定を完全に上書きします。先に export でバックアップを取ることを推奨します。

注意点

機能 4: 互換性チェック

本プラグインの動作要件を満たしているかを 7 項目で一目で確認できる表です。

チェック項目

項目 要件 判定ロジック
PHP version 7.4+ version_compare( PHP_VERSION, '7.4', '>=' )
WordPress version 6.0+ version_compare( get_bloginfo( 'version' ), '6.0', '>=' )
DOMDocument 拡張 必須 class_exists( 'DOMDocument' )
mbstring 拡張 必須 function_exists( 'mb_convert_encoding' )
External Object Cache 任意 wp_using_ext_object_cache()
WPML 任意 function_exists( 'icl_object_id' ) || class_exists( 'SitePress' )
Polylang 任意 function_exists( 'pll_get_post_translations' )

項目別の意味

PHP version (7.4+)

本プラグインは PHP 7.4 以上が必須です。?\? (null coalescing assignment) や arrow functions を使用しているためです。 PHP 8.0 / 8.1 / 8.2 / 8.3 でテスト済。

WordPress version (6.0+)

readme.txt 上は 6.1+ ですが、診断タブの実検査は 6.0+ に緩和されています。wp_cache_supports() 関数の利用が 6.1+ で安全のため、6.1 以上を推奨。

DOMDocument 拡張 (必須)

HTML→Markdown 変換のコア。多くの PHP ディストリビューションで標準搭載されていますが、minimal な構成では php-xml パッケージのインストールが必要な場合があります。

mbstring 拡張 (必須)

マルチバイト文字 (日本語・中国語等) の正確な処理に使用。mb_convert_encoding() が必須です。

External Object Cache (任意)

有効なら「キャッシュタブ」で object_cache backend を選択可能。Redis Object Cache plugin / W3 Total Cache / Object Cache Pro 等で実現。

WPML / Polylang (任意)

v1.0.0 では検出のみで自動連携なし。次バージョンで自動連携予定。

機能 5: md ホスト Bootstrap installer

md サブドメイン (例 md.example.com) のDocumentRoot に WordPress 入口となる index.php を自動生成・削除・状態確認 する機能です。SSH での手動配置が不要になります。

なぜ必要か

md サブドメインを使う構成では、md.example.com 用の DocumentRoot にも WordPress を起動するための入口 (3 行 PHP) が必要です。手動で書くなら以下のような内容:

<?php
// md.example.com/index.php (手動例)
define( 'WP_USE_THEMES', false );
require __DIR__ . '/../public_html/wp-blog-header.php';

本機能はこれを GUI から自動生成 / 検証 / 削除します。

サポート構成

構成タイプ レイアウト 典型例
sibling (兄弟) WP 本体と同じ親ディレクトリ配下、別フォルダ /home/user/public_html/wp/ + /home/user/public_html/md.example.com/
subdir (サブディレクトリ) ABSPATH 直下のサブディレクトリ (XServer 標準) /home/user/public_html/ + /home/user/public_html/md.example.com/ (= ABSPATH 内側)

非対応構成

UI 部品の対応表

セクション UI nonce action
WP 本体パス read-only 表示 (ABSPATH)
md 側 DocumentRoot text input (パス保存) ksmd_bootstrap_save_path
状態を再確認 button ksmd_bootstrap_check
index.php を生成 / 再生成 button (primary) ksmd_bootstrap_install
index.php を削除 button (link-delete) + confirm ksmd_bootstrap_uninstall
直前の削除を元に戻す button (24h 以内のみ表示) ksmd_bootstrap_restore

md 側 DocumentRoot の入力

md ホストのドキュメントルートを絶対パスで入力します。例:

入力後「パスを保存」ボタンで ksmd_settings.bootstrap_path に保存。サニタイズは ksmd_sanitize_bootstrap_path() で:

パス検証 (validation)

パス保存後、再び画面を開いたときに ksmd_bootstrap_check_status() が validation を実行します:

NG の場合は警告が表示され、後段の操作ボタン群が表示されません。

状態カード — 4 行の表示

表示行 内容
index.php の存在 ✓ 存在する / ✗ 存在しない (= md ホスト 403)
生成日時 本プラグインが生成した時刻 (installed_at)
構成タイプ sibling または subdir
md ホスト動作確認 (verify) SUCCESS / PENDING / FAILED + HTTP コード + メッセージ

3 重チェック (marker + sha256 + version)

index.php の同一性検証は以下 3 つを照合します:

  1. marker: コメント内の固定文字列 KSMD-BOOTSTRAP-MARKER
  2. sha256: 期待される全ファイル hash (sha256)
  3. version: コメント内のテンプレートバージョン (v1)

1 つでも一致しない場合は「手動編集の可能性あり」と表示され、上書き再生成は確認を促す挙動になります。

install アクション

「index.php を生成」ボタンを押すと:

  1. nonce ksmd_bootstrap_install verify
  2. パス validation 再実行
  3. テンプレートを sibling/subdir 別にレンダリング (ABSPATH を相対パス化)
  4. tempnam → atomic rename でファイル書き込み (TOCTOU 防止)
  5. chmod 0644
  6. meta (installed_at, layout_type 等) を ksmd_bootstrap_meta option に保存
  7. verify として md ホストへ HTTP リクエスト + HMAC ヘッダ確認

uninstall アクション (confirm 必須)

「index.php を削除」ボタンは JS confirm dialog 付き:

md ホストの index.php を削除します。md.host が一時的に 403 になります。続行しますか?

確認後:

  1. 削除前にファイル全体を ksmd_bootstrap_last_removed_backup option にバックアップ (24 時間有効)
  2. unlink() で削除
  3. meta を更新 (削除フラグ + removed_at)

restore アクション (24h 以内のみ)

削除から 24 時間以内 (KSMD_BOOTSTRAP_BACKUP_TTL = DAY_IN_SECONDS) は「直前の削除を元に戻す」ボタンが表示されます。クリックすると:

  1. backup から元ファイルを atomic write で復元
  2. backup を削除 (1 回限りの巻き戻し)
  3. meta も復元前の状態へ

24 時間を過ぎた backup は ksmd_bootstrap_expire_backup_if_old() によって自動削除され、ボタンは消えます。

verify (md ホスト動作確認)

install 後の verify は WP HTTP API で md ホストに GET リクエストを発行し、HMAC ヘッダを付けて応答内容と組み合わせて成否判定します:

SSL 検証は ksmd_bootstrap_sslverify filter で上書き可能 (ローカル開発で self-signed cert を使う等)。

内部挙動 — 設定値が読まれる場所

access_log_* 系

bootstrap_path 系

関連 filter

typical configurations

パターン A — 開発環境 (アクセスログ ON、保持 30 日)

パターン B — 本番 GDPR 対応

パターン C — 軽量本番 (ログ無効)

用途: アクセス解析を別ツール (Cloudflare Analytics 等) で取っていて DB 圧迫を避けたい。

パターン D — XServer サブドメイン構成

よくある質問

Q. Test renderer で実 URL を叩いても md 化されない

A. プレビュー機能はサーバ内で WP_Query を内部実行する設計です。外部 HTTP リクエストを発行するわけではないので、URL がメインサイト (www) でアクセス可能であれば内部解決できます。404 が返る場合は対象範囲タブで該当 post_type / route が ON になっているか確認してください。

Q. アクセスログを ON にしたのに表示されない

A. ログは md サブドメイン側のリクエストのみ記録されます。管理画面 (wp-admin) のリクエストや www 側は対象外。md.example.com に実際にアクセスしてから設定タブをリロードしてください。

Q. アクセスログテーブルのサイズはどのくらいになる?

A. 1 行あたり概算 1-2 KB。月間 1 万 PV なら月 10〜20 MB、100 万 PV で 1〜2 GB 程度。retention 7 日でも実テーブルからは消えないため、定期的に「アクセスログを全削除」ボタンで TRUNCATE するか、cron で ksmd_access_log_clear() を呼ぶ運用を推奨。

Q. import で「不正な JSON」エラー

A. ファイルが UTF-8 BOM 付きで保存されているか、改行コードが破損している可能性があります。テキストエディタで UTF-8 (BOM なし) で保存し直してください。

Q. 互換性チェックで External Object Cache が「無効」

A. これは「未検出」と同義で、必須ではありません。Redis 等を導入する場合のみ ON になります。判定は ✓ OK のままです (任意項目のため)。

Q. Bootstrap installer のパスを保存したら「open_basedir 制約」エラー

A. PHP の open_basedir 設定が指定パスを許容していません。Web サーバの設定 (Apache の php_admin_value open_basedir、または php.ini) で md ホストの DocumentRoot を open_basedir に追加してください。

Q. install ボタンで「権限がない」エラー

A. PHP プロセスが md ホストの DocumentRoot に書き込み権限を持っていません。次のいずれかの対処:

Q. verify が PENDING のままで進まない

A. md.example.com への DNS が伝播していないか、SSL 証明書が未発行の可能性があります。「動作確認」セクション (一般タブ末尾) で md ホストにブラウザから直接アクセスして確認してください。

Q. uninstall した直後に再 install したら backup は?

A. 再 install で新しい index.php が生成されるため、既存の backup は意味を失います。restore ボタンは表示されますが、復元すると新生成版が backup の旧版で上書きされます。意図しない場合は注意。

Q. test renderer の出力に Schema.org ヘッダが入っていない

A. 「出力タブ」で「Schema.org ヘッダブロック」がチェック済みか確認してください。test renderer は通常の md 化パイプラインを通るため、この設定が反映されます。

Q. アクセスログの IP 匿名化 ON/OFF を切り替えたら、過去ログも変わる?

A. いいえ。匿名化は記録時に適用されるため、過去のログは設定変更前のフォーマットのままです。過去ログも匿名化したい場合は手動で全削除して再度 ON にしてください。

Q. config の export で password / secret は含まれる?

A. このプラグインは password / secret を保管しないため、export JSON に機密値はありません。bootstrap_path 等のサーバパスのみ。それでもサポートに送る前に確認推奨。

Q. Bedrock 構成で動かない

A. Bedrock (wp/ + vendor/) は非対応とドキュメントに明記されています。Bootstrap installer は使用せず、index.php を Bedrock 流に手動で書く必要があります。

Q. md ホスト Bootstrap installer を使わずに index.php を手書きしたい

A. 可能です。最小例 (sibling 構成):

<?php
// md.example.com/index.php
define( 'WP_USE_THEMES', false );
require dirname( __DIR__ ) . '/path/to/wp/wp-blog-header.php';

marker / sha256 が一致しないため診断タブでは「手動編集の可能性あり」と表示されますが、本プラグインの動作には影響ありません。

関連