DOCUMENT · 14.9 KB
skills/wordpress-migration/references/TROUBLESHOOTING.md
Workspace snapshot · 09/04 13:33
WordPress 移行 トラブルシューティング
症状 → 原因 → 対処。SKILL.md と RUNBOOK.md の手動確認結果から引く。
まず確認する共通の3点:
wp option get siteurl ; wp option get home # 期待値と一致するか
wp config get WP_SITEURL --type=constant # 定数がDBを上書きしていないか
wp config get WP_HOME --type=constant
wp plugin list --status=active # キャッシュ/セキュリティ系が動いていないか
S1. 真っ白(白画面) / HTTP 500
原因の切り分け順:
- PHPの致命的エラー。
wp-config.phpに一時的に次を入れてログへ出す。define('WP_DEBUG', true); define('WP_DEBUG_DISPLAY', false); define('WP_DEBUG_LOG', true);wp-content/debug.logとサーバーのエラーログを読む。推測で直さない。 - PHPバージョン差異。移行先のPHPが新しく、テーマ/プラグインが非対応。 → 移行先のPHPを移行元と同じバージョンへ下げて復旧させ、PHP更新は移行完了後の別作業にする。
.htaccessの持ち込み。Apache→Nginx、または事業者固有ディレクティブが不正。 →.htaccessを退避し、wp rewrite flush --hardで標準の内容を再生成する。- メモリ不足。
define('WP_MEMORY_LIMIT', '256M');とphp.iniのmemory_limitを確認。 advanced-cache.php/object-cache.phpの残骸。キャッシュプラグインを外したのにドロップインが残っている。 → 両ファイルを退避する。- プラグイン起因の切り分け:
全停止は影響を説明して承認を得てから行い、復旧後は記録した一覧だけを戻す。wp plugin list --status=active --field=name > ~/active-plugins-before-debug.txt wp plugin deactivate --all # 復旧したら1つずつ有効化して原因を特定する while IFS= read -r plugin; do wp plugin activate "$plugin"; done < ~/active-plugins-before-debug.txt
S2. 「データベース接続確立エラー」
wp-config.phpのDB_NAME/DB_USER/DB_PASSWORD/DB_HOSTが移行先の値になっていない。DB_HOSTはlocalhostでないことが多い(事業者指定のホスト名やソケットパス)。- DBユーザーに権限が付与されていない。
$table_prefixが実際のテーブルと違う → 接続はできるが「インストール画面」が出る。- 確認:
wp db check wp db tables
S3. リダイレクトループになる(無限にリダイレクトしました)
移行事故の代表格。原因は4系統。
siteurlとhomeの不整合、または片方が旧ドメイン。wp option get siteurl ; wp option get home wp option update siteurl 'https://new.example.jp' wp option update home 'https://new.example.jp'wp-config.phpの定数がDBを上書きしている。WP_SITEURL/WP_HOMEが旧値のまま。 → 定数を新URLへ更新するか削除する。FORCE_SSL_ADMINとロードバランサ/リバースプロキシの組み合わせ。 プロキシがバックエンドへHTTPで渡しているのにWordPress側がHTTPSを強制し、永久に往復する。
(if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; }wp-config.phpのrequire_once ABSPATH . 'wp-settings.php';より前に置く).htaccess/ Nginx側のリダイレクトと、プラグインの常時SSL・www正規化が二重に効いている。 → どちらか片方に統一する。curl -sIL https://new.example.jp | grep -i '^location'で連鎖を見る。
curl -sIL の Location 列を読み、同一URLへの回帰や不自然に長い連鎖があれば切替を止める。
S4. トップは出るが下層ページが全部 404
- パーマリンク設定の未反映。
管理画面の「設定 > パーマリンク」を開くだけでも再生成される。wp rewrite structure '/%postname%/' --hard wp rewrite flush --hard .htaccessが無い / 書き込めない(Apache)。WordPress標準ブロックを手で戻す。AllowOverride None(Apache)で.htaccessが読まれていない → サーバー設定側で許可する。- Nginx に
try_files ... /index.php?$args;が無い → サーバー設定を修正する。 - 移行元がサブディレクトリ設置で、移行先がドキュメントルート直下になった(またはその逆)。
→
siteurl/homeのパス部分を実際の設置場所に合わせる。
S5. ウィジェット・カスタマイザー・プラグイン設定・ページビルダーのレイアウトが消えた
シリアライズデータの破損。 原因はほぼ一つで、sed や SQL の REPLACE() でURLを置換したこと。
s:29:"https://old.example.com/about" ← 宣言長 29
s:29:"https://new-site.example.jp/about" ← 実長は違う → unserialize() が false を返す
- 復旧方法は置換前のバックアップからのリストアのみ。 壊れた値を手で直すのは現実的でない。
wp db import ~/pre-replace-XXXXXXXXXXXX.sql - リストア後、必ず
SKILL.mdStep 5 の6形式を、wp search-replace --preciseの dry-runからやり直す。 - 症状が出るのは置換の数時間後であることが多い(キャッシュが切れてから)。 置換直後の目視確認では気づけないため、置換後は必ずウィジェット・カスタマイザー・ ページビルダーの編集画面を開いて中身を確認する。
- Elementor / Divi など、JSONを入れ子で保存するビルダーは
エスケープ形(
https:\/\/old.example.com)の置換漏れでも壊れる。SKILL.mdStep 5 はこの形を別パスとして処理する。
S6. 画像が表示されない/URL が旧ドメインのまま
- DB内の残存を数える。
0件でなければ置換漏れ。エスケープ形・プロトコル相対形も含めて再置換する。wp db search 'old.example.com' --all-tables-with-prefix --stats uploadsが転送されていない。ファイル数とサイズを両側で照合する。find wp-content/uploads -type f | wc -l ; du -sh wp-content/uploads- ファイルはあるが 403。パーミッション・所有者がWeb実行ユーザーと合っていない。
- サムネイルだけ出ない。中間サイズが未生成。
wp media regenerate --yes - CDN / オフロードプラグインが旧ドメインを指している。プラグイン設定側のURLを更新する。
wp-config.phpのWP_CONTENT_URL/UPLOADSが旧値のまま。
S7. 混在コンテンツで鍵マークが出ない
- HTML内に
http://の絶対URLが残っている。
(同一ホストのスキーム引き上げ。wp search-replace 'http://new.example.jp' 'https://new.example.jp' \ --all-tables-with-prefix --precise --report-changed-only --skip-columns=guid --dry-run--oldにスキームを明示すること) - 外部リソース(他サイトの画像、古い埋め込み、フォント、アナリティクス)が
http://。 → 自ドメインの置換では直らない。該当箇所を個別に修正する。 - CSS/JS内のハードコードURL、テーマの設定値、
wp_options内のシリアライズ値。 - 対症療法としてのアップグレード指示(
Content-Security-Policy: upgrade-insecure-requests)は 原因を隠すだけ。まず実体を直す。
S8. 移行後に検索から消えた/noindex が残っている
ステージング本番化で最も損失が大きく、最も気づかれにくい事故。
wp option get blog_public # 1 が公開。0 なら検索避けが有効
wp option update blog_public 1
- HTMLの
<meta name="robots" content="noindex">、またはX-Robots-TagHTTPヘッダー。 ヘッダー側はブラウザで見えないので気づきにくい。curl -sI https://new.example.jp | grep -i x-robots-tag - SEOプラグイン(Yoast / Rank Math / SEO SIMPLE PACK)側の noindex 設定が別に存在する。 サイト全体設定と、投稿タイプごとの設定の両方を見る。
- サーバー/事業者のステージング機能が自動でヘッダーを付けている場合がある(機能をオフにする)。
- Basic認証が残っていると検索エンジンはクロールできない。
curl -sIが 401 を返さないか確認。 - 修正後、Search Console でサイトマップを再送信。ドメイン変更ならアドレス変更ツールを使う。
- 旧ドメイン→新ドメインの301は最低1年維持する。評価の移転はリダイレクトが前提。
S9. canonical が旧ドメインを指している
- DB内の置換漏れ(S6の手順1)。
- SEOプラグインに canonical のベースURLがハードコードされている。
- キャッシュ済みHTMLが配信されている。
加えてCDN側のキャッシュもパージする。wp cache flush ; wp transient delete --all - 放置すると新ドメインがインデックスされない。公開判定では致命的な未完了として扱う。
S10. robots.txt に Disallow: / が残っている
- 物理ファイルが存在する場合、WordPressの仮想 robots.txt は返らない。
ルート直下の
robots.txtを確認し、ステージング用の内容なら削除または修正する。 - 物理ファイルが無く
blog_publicが 0 なら、WordPress が自動でDisallow: /を返す(S8)。 robots.txtが 404 の場合、パーマリンク再生成(S4)で仮想robots.txtが復活することがある。- robots.txt によるブロックは
noindexとは別問題。両方確認する。
S11. <title> が空 / canonical が無い
- テーマが正しく読み込まれていない(テーマファイル未転送、テーマ名ディレクトリの大文字小文字違い)。
Linux間でも移行元がmacOS/Windows経由だと大小が変わることがある。
wp theme list - SEOプラグインが停止している。
- ページが実際にはエラーページを返している(S1と併発)。
- 単独なら軽微な場合もあるが、HTTPエラーなどと同時に出ている場合は テーマ/プラグインの読み込み失敗を疑う。
S12. 到達不能/DNS がまだ旧サーバーを指している
dig +short new.example.jp
dig +short @8.8.8.8 new.example.jp
dig +short @1.1.1.1 new.example.jp
- TTLが経過していない。下げていなかった場合は最大で旧TTL(例: 3600秒〜86400秒)待つ。
- 自端末やルーターのDNSキャッシュ。ネームサーバーを直接指定して確認する。
- ネームサーバー自体が旧事業者のまま(Aレコードを変えても、権威が別ならそちらが引かれる)。
- CAA レコードで証明書発行が拒否されている(SSLが張れない場合)。
- 切替前の検証は hosts ファイルで行う(RUNBOOK Phase 9)。DNSの浸透を待たずに検証できる。
S13. フォームからメールが届かない
移行で壊れやすいが、移行後の確認から漏れやすい組み合わせ。
- 送信元ドメインのSPF / DKIM / DMARC が旧サーバーのIPを許可している。 → 新サーバーのIPまたは送信サービスを許可するようDNSを更新する。
- 事業者が
mail()を許可していない、またはSMTP必須。→ SMTPプラグインで明示設定する。 Fromアドレスが自ドメインでないため受信側で拒否される。- 確認:
wp eval 'var_dump(wp_mail("test@example.com","migration test","body"));'trueでも受信側で捨てられることがあるため、実際の受信箱で確認する。
S14. 予約投稿・定期処理が止まった
DISABLE_WP_CRONが定義されていて、外部cronが旧ドメインのURLを叩いている。 → 外部cronの設定を新URLへ更新する。- 溜まったイベントを確認する。
wp cron event list wp cron test - サーバーのcronジョブ自体が移行されていない(サーバー設定は移行対象に入らない)。
S15. ログインできない / ログインしても管理画面へ入れない
- 認証ソルトキーを再生成したため既存セッションが無効になった(正常。再ログインで解決)。
COOKIE_DOMAINが旧ドメインのまま定義されている → 更新または削除する。- ログイン後にループする場合はS3の系統。
- パスワードをリセットする。値をコマンドライン引数へ直接書かず、WP-CLIの対話入力を使う:
wp user update <login> --prompt=user_pass - セキュリティプラグインのIP制限・国別制限が新環境で誤作動している → プラグインディレクトリ名を一時的に変更して無効化する。
S16. 「置換したのに変わらない」
原因は次のいずれか。上から順に確認する。
wp-config.phpのWP_SITEURL/WP_HOME定数がDBの値を上書きしている(最頻)。- ページキャッシュ(プラグイン / サーバー / CDN / ブラウザ)が古いHTMLを返している。
- 置換対象のDBが違う(複数DBがある、ステージングを見ている)。
--oldの指定が実際の格納形式と一致していない(www.の有無、ポート付き、エスケープ形)。wp db search 'old.example' --all-tables-with-prefix --stats- 接頭辞外のテーブルに格納されている(
search-replaceは--all-tables-with-prefixの範囲外を触らない)。wp db tables --all-tablesとwp db tables --all-tables-with-prefixの差分を確認する。
判断に迷ったときの原則
- 推測で本番を触らない。 症状を再現できるか、ログに根拠があるかを先に確認する。
- 1回に1つだけ変える。 複数同時に変えると、直った理由も壊れた理由も分からなくなる。
- 復旧の見込みが立たない場合、時間を使い切る前にロールバック(RUNBOOK Phase 13)へ切り替える。 判断のデッドラインは作業開始前に利用者と合意しておく。
- WARN を「たぶん平気」で飛ばさない。移行の事故は WARN の積み残しから起きる。
MIT License. Provided as-is, without warranty. Part of PENGIN Tools.