← CLAUDE-PENGIN-TOOLS
DOCUMENT · 12.1 KB

skills/wordpress-triage/SKILL.md

Workspace snapshot · 09/04 13:33


name: wordpress-triage description: Diagnose a broken or misbehaving WordPress site in a fixed triage order instead of guessing. Use when a site shows a white screen, HTTP 500, a redirect loop, 404s on every subpage, a database connection error, a locked-out wp-admin, missing images, sudden slowness, or when something broke right after an update, a migration or a plugin change. Preserves evidence before changing anything, separates stabilising the site from finding the cause, verifies fixes past caches and CDNs, and stops and switches procedure if signs of a compromise appear, because restoring a backup can restore the backdoor with it. license: MIT

WordPress 障害切り分け

壊れたサイトの前で最もやってはいけないのは、心当たりのある場所から順に触ること。 直ることもあるが、直らなかったとき「元の状態」が失われ、原因も分からなくなる。

このSkillは、証拠を残す → 止血する → 原因を特定する の順序を固定する。

絶対に守る順序

  1. 何かを変更する前に、現状を記録する。 直し始めた瞬間に証拠は消える。
  2. 「復旧」と「原因究明」を混ぜない。 サイトが落ちているなら、まず戻す。原因はその後。
  3. 推測で設定を変えない。 ログを読む。読めない場合は、読める状態を作るのが先。
  4. 一度に1つだけ変える。 2つ同時に変えると、どちらが効いたか永久に分からない。
  5. 「直った」をキャッシュ越しに判断しない。 ブラウザ・プラグイン・CDN・サーバーの4層を疑う。
  6. 改ざん・侵害の兆候が出たら、切り分けを中止する。 手順が変わる(Step 6)。

Step 0. 依頼者と範囲を確認する

  • 対象サイトの管理権限を持っているか。持っていない場合は作業しない。
  • いつから、何をした直後に起きたか(更新/移行/プラグイン追加/サーバー作業/何もしていない)。
  • 現在も継続しているか、断続的か。
  • ECや会員制で、売上・個人情報が動いているか。 動いている場合、DBを戻す判断の重みが変わる。

「何もしていないのに壊れた」は、たいてい自動更新かサーバー側の変更か期限切れ(SSL証明書、 ドメイン、有料プラグインのライセンス)。この3つを最初に疑う。

Step 1. 証拠を保全する(変更の前に)

この記録を取る前に、設定ファイルを書き換えない。

mkdir -p ~/wp-triage/$(date +%Y%m%d-%H%M) && cd ~/wp-triage/$(date +%Y%m%d-%H%M)

curl -sI  https://example.com | tee headers.txt | head -1      # ステータス行
curl -sIL https://example.com | grep -i '^location' > redirects.txt   # リダイレクト連鎖
date > captured-at.txt

WP-CLIが動く場合は、あわせて状態を控える。WP-CLIが動かないこと自体が重要な情報なので、 エラーが出たらそのエラー文も保存する。

wp core version              > core-version.txt 2>&1
wp plugin list --format=csv  > plugins.csv       2>&1
wp theme list --format=csv   > themes.csv        2>&1
wp option get siteurl        > siteurl.txt       2>&1
wp option get home           > home.txt          2>&1

サーバーのエラーログとPHPログの、現在の末尾位置を控える。ここから後に出た行が、今回の作業で 発生したものになる。

tail -n 50 wp-content/debug.log > debug-log-before.txt 2>/dev/null || echo "debug.log 無し" > debug-log-before.txt

Step 2. 症状を分類する(ここで経路が決まる)

観測分類進む先
HTTP 500 / 真っ白 / Fatal errorT1 実行時エラーStep 3
「データベース接続確立エラー」T2 DB接続Step 4
リダイレクトが終わらないT3 リダイレクトループStep 5
トップは出るが下層が全部404T4 リライトreferences/DECISION-TREE.md T4
管理画面に入れない(ログインは通る/通らない)T5 ログインreferences/DECISION-TREE.md T5
表示はされるが崩れている・画像が出ないT6 アセットreferences/DECISION-TREE.md T6
極端に遅い(落ちてはいない)T7 パフォーマンスreferences/DECISION-TREE.md T7
身に覚えのないページ・リダイレクト・管理者T8 改ざんの疑いStep 6(最優先)

分類できないまま次へ進まない。 「たぶんプラグイン」で全停止すると、T2やT8を見逃す。

Step 3. T1 実行時エラー — まずエラーを読める状態にする

真っ白は「情報が無い」のではなく、情報が画面に出ていないだけ。ログへ出す。

// wp-config.php に一時的に追加(作業後に必ず戻す)
define('WP_DEBUG', true);
define('WP_DEBUG_DISPLAY', false);   // 画面には出さない(訪問者に見せない)
define('WP_DEBUG_LOG', true);

WP_DEBUG_DISPLAY は必ず false。 true にすると、パスや構造が訪問者に露出する。

再現させてから wp-content/debug.log とサーバーのエラーログを読む。 Fatal error の1行目に、どのファイルの何行目かが出る。そこが起点。推測より速い。

読めた原因が特定のプラグイン/テーマなら、そのプラグイン1つだけを止める(全停止しない)。

wp plugin deactivate <slug>

原因が読めない場合に限り、切り分けとして全停止する。その前に必ず現在の有効一覧を保存する。

wp plugin list --status=active --field=name > ~/wp-triage/active-before.txt
wp plugin deactivate --all
# 復旧したら1つずつ戻す
while IFS= read -r p; do wp plugin activate "$p"; done < ~/wp-triage/active-before.txt

全停止はサイトの機能を止める(フォーム、カート、会員)。実行前に影響を説明して同意を得る。

その他の定番: PHPバージョン差異、メモリ不足、advanced-cache.php / object-cache.php の残骸、 持ち込んだ .htaccess。詳細は references/DECISION-TREE.md T1。

Step 4. T2 DB接続エラー — 4つしか原因がない

  1. wp-config.php の DB_NAME / DB_USER / DB_PASSWORD / DB_HOST が違う。 DB_HOST は localhost とは限らない(事業者指定のホスト名やソケットパス)。
  2. DBサーバーが落ちている/接続数上限。サーバー側の問題で、WordPress側では直せない。
  3. DBユーザーの権限が外れた。
  4. $table_prefix が実テーブルと不一致 → 接続はできて「インストール画面」が出る。
wp db check
wp db tables

移行直後なら1、何もしていないなら2を最初に疑う。 2の場合、事業者の障害情報を確認する。 wp-config.php を書き換える前に、元のファイルをコピーして残す。

Step 5. T3 リダイレクトループ — 連鎖を見る

curl -sIL https://example.com | grep -iE '^(HTTP|location)'

同じURLへ戻る/不自然に長い連鎖があれば、原因は次の4系統。

  1. siteurl と home の不整合、または片方が旧ドメイン
  2. wp-config.php の WP_SITEURL / WP_HOME 定数がDBを上書きしている
  3. リバースプロキシ/ロードバランサとHTTPS強制の組み合わせ
  4. .htaccess / Nginx側のリダイレクトと、プラグインの常時SSL・www正規化が二重掛け

移行直後なら1と2。 詳細と修正手順は references/DECISION-TREE.md T3。

Step 6. T8 改ざんの疑い — ここだけ手順が変わる

次のいずれかがあれば、通常の切り分けを中止する。

  • 身に覚えのない管理者ユーザー、投稿、リダイレクト、外部への通信
  • 検索結果に無関係な言語のページが出る
  • wp core verify-checksums / wp plugin verify-checksums --all が不一致を返す
  • コアファイルやテーマに、更新していないのに新しい更新日時のファイルがある
wp core verify-checksums
wp plugin verify-checksums --all
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

なぜ手順が変わるか: バックアップからの復元で、バックドアも一緒に復元されうる。 侵入がいつ始まったか分からないまま「動いていた頃のバックアップ」へ戻すと、同じことが繰り返される。

このSkillは侵害対応の完全な手順は提供しない。次を行って、専門的な対応へ引き継ぐ。

  1. 現状を保全する(消さない・上書きしない)。ファイル一覧とタイムスタンプ、DBダンプを別保管する。
  2. 全管理者のパスワードと、DB・FTP・ホスティングの認証情報を変更する。
  3. 侵害の可能性と、個人情報が扱われているかをサイト所有者へその時点で伝える。 個人情報が関わる場合、技術的な復旧より先に報告義務の確認が必要になることがある。
  4. 復旧は「クリーンな環境へ、検証したコンテンツだけを移す」方針で計画する。

Step 7. 「直った」を確認する

修正したら、4層すべてを越えて確認する。1層でも古いものを見ていると誤判定する。

wp cache flush
wp transient delete --all
curl -sI 'https://example.com/?nocache='$(date +%s) | head -1   # クエリを付けてキャッシュを回避
  1. ブラウザ(シークレットウィンドウ/別端末)
  2. WordPress側キャッシュプラグイン(パージ)
  3. CDN(パージ)
  4. サーバー側キャッシュ(事業者の管理画面)

そのうえで、壊れていても200を返す箇所を開く。トップページの200は復旧の証拠にならない。

  • 下層ページ 2〜3枚
  • 問い合わせフォームの送信(受信箱まで)
  • 管理画面へのログイン
  • 決済・カート(ECの場合)

Step 8. 後始末と記録

  • WP_DEBUG など一時的に入れた設定を戻した
  • 切り分けで停止したプラグインを、Step 3で保存した一覧どおりに戻した
  • debug.log を残したままにしない(公開ディレクトリから読めることがある)
  • 何が原因で、何を変えて直ったかを1行で書いた
  • 再発防止を決めた(自動更新の扱い、監視、バックアップ頻度)
  • 原因が特定できなかった場合、特定できなかったと書く

記録に書いてはいけないもの: DB名、DBユーザー名、パスワード、変更後の管理画面URL、 バックアップの完全パス。この記録は共有される。


止まる条件(該当したら作業を止めて確認する)

  1. サイトの管理権限を持っていることが確認できない。
  2. 改ざん・侵害の兆候がある(Step 6へ。通常の切り分けを続けない)。
  3. 個人情報・決済情報が漏えいした可能性がある。技術対応より先に所有者へ伝える。
  4. 原因が不明なまま、DBのリストアを求められた。 更新後に入った注文・問い合わせ・会員登録が消える。 影響範囲を提示してから判断する。
  5. 「とりあえず全部戻して」と、記録を取る前の変更を求められた。
  6. サーバー事業者側の障害の可能性があるのに、WordPress側の変更を求められた。
  7. 復旧を急かされ、一度に複数の変更をまとめて行うよう求められた。

このSkillが行わないこと

  • 侵害インシデントの完全な対応(Step 6で保全と引き継ぎまで)
  • 法的・報告義務の判断
  • サーバー契約、DNS、決済設定の変更
  • 原因が特定できていない段階での「とりあえずの再インストール」