← CLAUDE-PENGIN-TOOLS
DOCUMENT · 16.7 KB

skills/wordpress-maintenance/SKILL.md

Workspace snapshot · 09/04 13:33


name: wordpress-maintenance description: Run WordPress update and maintenance work so that a broken site can always be restored. Use when the user asks to update WordPress core, plugins or themes, to run weekly or monthly maintenance, to judge whether an update is safe to apply, to verify a site after updating, or to roll a plugin or theme back to a previous version. Records the exact version state before touching anything, updates in separated batches instead of all at once, verifies the paths that keep returning HTTP 200 while actually being broken (forms, checkout, login, page-builder editing screens), and prepares a rollback command for every change before making it. Does not rely on WordPress core rollback alone, which only covers a failed update process or a PHP fatal error.

WordPress 保守・更新

まず scripts/plan_updates.py を使い、WP-CLIから取得した更新候補を低・中・高リスクの束へ分ける。 このスクリプトはWordPressを書き換えない。更新の実行は、出力された計画を利用者へ示した後に行う。

wp plugin list --update=available --format=json > updates.json
python scripts/plan_updates.py updates.json --output update-plan.md

更新作業の失敗は「更新したから」起きるのではない。戻せない状態で更新したから起きる。 このSkillは、戻せる状態を先に作ることを順序として固定する。

絶対に守る順序

  1. 更新前のバージョン一覧と、更新対象を戻せるバックアップが無い状態で更新しない。 バージョン一覧は戻し先を特定する記録であり、それだけでは復元できない。記憶や画面のスクロールに頼らない。
  2. 全部まとめて更新しない。 束を分ける。一括更新して壊れると、原因の特定に更新そのものより時間がかかる。
  3. 更新後の確認は「サイトが開くか」で終わらせない。 壊れていてもHTTP 200を返す箇所がある。
  4. 戻し方を先に決める。 どのコマンドで、どのバージョンへ戻すかを更新前に書き出す。
  5. 本番で試さない。 ステージングがある場合はそこが先。無い場合は、無いという事実を利用者へ伝えてから進む。

コア標準のロールバックが守ってくれる範囲(誤解しやすい)

WordPress本体にもロールバックはあるが、カバー範囲が狭い。これを万能だと思って進めると事故になる。

機能何を拾うか拾わないもの
コア更新の自動ロールバック(WP 3.7〜)コア更新処理そのものの失敗更新後の表示崩れ、プラグイン互換性
手動更新のロールバック(WP 6.3〜)プラグイン/テーマの更新処理が失敗したとき、wp-content/upgrade-temp-backup/ から旧版を戻す更新が成功した上で壊れたケース
自動更新のロールバック(WP 6.6〜)自動更新後のループバック要求でPHPのfatal errorを検出したときfatal errorにならない不具合

標準機能が主に守るのは、更新処理そのものの失敗と、自動更新後に検出できるPHP fatal error。 実務で最も多い「サイトは普通に開くのに、問い合わせフォームだけ送信できない」「カートが落ちる」 「ページビルダーの編集画面が開かない」は、どれも拾われない。 そこはこのSkillの手順で拾う。

保守の型を最初に決める

型状況重点
M1 定期保守月次・週次の通常更新束分け、更新後確認、記録の残し方
M2 緊急セキュリティ更新脆弱性の公表を受けた即時更新影響確認を短縮しつつ、記録とロールバック手段は省略しない
M3 停滞サイトの復旧長期間更新されておらず、差分が大きい一気に上げない。 段階更新とステージング必須
M4 更新事故の復旧すでに壊れているまず戻す。原因調査はその後
M5 更新可否の判断のみ「これ上げて大丈夫?」実行しない。判断材料だけ出す

型が判定できるまで更新コマンドを実行しない。 特にM3をM1として扱うのが典型的な事故。


Step 0-B. レンタルサーバーで先に潰しておくこと

これは実測で出た事故パターンである。 同じPENGIN ToolsのWordPress Migration Skillを Xserverの実WordPressでE2Eしたとき、机上レビューでは0件だった不具合が5件出た。 そのうち4件はこの種の環境差で、保守の手順にも同じ形で効く。

環境差何が起きるか対処
/bin/sh が dashdiff <(...) <(...) などのbash専用構文が構文エラーで落ちる一時ファイルを経由する(Step 6の記述はそうしてある)。bash script.sh で明示的に起動してもよい
WP-CLIがstdinを消費するwhile read ループの中で wp を呼ぶと、残りの行が黙って飛ぶループ内の wp は wp ... < /dev/null にする
Basic認証curl -sI https://example.com が 401 を返し、更新前後の比較が両方とも「壊れている」に見えるcurl -u user:pass を使うか、比較対象をHTTP以外(wp option get、投稿件数)へ寄せる。認証情報は記録ファイルに書かない
WAF更新や管理画面POSTが 403 で弾かれ、「プラグインのせい」に見える作業前にWAFの一時解除可否を確認する。403が出たら、まずWAFを疑ってから切り分けへ進む
サブディレクトリ運用https://example.com を叩いても対象サイトではないURLは推測せず wp option get home の値を使う

変数の固定も先にやる。 $(date +%Y%m%d) を各コマンドで書くと、 作業が日付をまたいだ瞬間に保存先が変わり、バックアップと記録が別ディレクトリに散る。

WORKDATE=$(date +%Y%m%d)
WORKDIR=~/wp-maint/$WORKDATE
mkdir -p "$WORKDIR" && chmod 700 "$WORKDIR" && cd "$WORKDIR"

以降、日付は $WORKDATE、保存先は $WORKDIR を使う。

Step 1. 環境を確定する

更新の前に、その環境で何ができるかを確定する。移行Skillと同じく、WP-CLIの有無で経路が変わる。

wp --version || echo "WP-CLI が無い → Step 7(管理画面経由)へ"
echo "$0"            # 実行中のシェル。sh / dash なら Step 0-B の1行目が効く
wp option get home   # 対象サイトの実URL。以降の curl はこの値を使う

日本のレンタルサーバーではWP-CLIが標準提供されていないことが多い。無いことを前提外として扱わない。 WP-CLIが無い場合でも保守はできるが、記録の取り方が変わる(Step 7)。

Step 2. 現状を読み取り専用で記録する

この出力をファイルへ保存するまで、更新を実行しない。

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

wp core version                              > core-version.txt
wp plugin list --fields=name,status,version,update,update_version --format=csv > plugins-before.csv
wp theme  list --fields=name,status,version,update,update_version --format=csv > themes-before.csv
wp option get blog_public                    > blog_public.txt
wp cron event list --format=csv              > cron-before.csv 2>/dev/null || true
wp plugin list --status=active --field=name  > active-plugins.txt

保存した plugins-before.csv は戻し先を特定する記録。実際に戻すには、旧版パッケージ、 更新前ディレクトリ、ホスティング側スナップショットのいずれかも必要になる。

あわせて、更新前の見た目と挙動の基準を取る。

HOME_URL=$(wp option get home)                # 推測しない。サブディレクトリ運用でもこれで合う
curl -sI "$HOME_URL" | head -1                # 200 か
curl -s  "$HOME_URL" | wc -c                  # バイト数を控える(後で極端に変わったら疑う)

401が返ったらBasic認証、403が返ったらWAFを先に疑う(Step 0-B)。 どちらもプラグインの不具合ではないのに、切り分けを丸ごと誤らせる。

Step 3. 更新候補を出す(まだ実行しない)

wp core check-update
wp plugin update --all --dry-run
wp theme  update --all --dry-run

プラグイン候補は、同梱の読み取り専用Plannerでも束分けできる。

wp plugin list --update=available --format=json > updates.json
python scripts/plan_updates.py updates.json --output update-plan.md

--dry-run は「何が更新されるか」だけを表示する。この一覧を利用者へ提示する。

各項目について、次を確認してから束を決める。

  • メジャー更新か(1.9 → 2.0)。メジャーは単独で更新し、単独で確認する。
  • サイトの中核か(EC、フォーム、会員、ページビルダー、キャッシュ、セキュリティ)。中核は単独。
  • 有料/独自プラグインか。更新元がwordpress.orgでない場合、wp plugin install --version= で戻せない。 戻せないものは、更新前にディレクトリを丸ごと退避する(Step 4)。

Step 4. 戻せる状態を作る

mkdir -p ~/wp-maint/$(date +%Y%m%d)
chmod 700 ~/wp-maint/$(date +%Y%m%d)
wp db export ~/wp-maint/$(date +%Y%m%d)/db-before-update.sql
chmod 600 ~/wp-maint/$(date +%Y%m%d)/db-before-update.sql
[ -s ~/wp-maint/$(date +%Y%m%d)/db-before-update.sql ] && tail -c 100 ~/wp-maint/$(date +%Y%m%d)/db-before-update.sql

# 更新対象のコードと主要設定も退避する。uploadsは更新対象外なので既定では除く。
BACKUP_LIST=~/wp-maint/$(date +%Y%m%d)/code-backup-files.txt
printf '%s\n' wp-content/plugins wp-content/themes wp-config.php > "$BACKUP_LIST"
[ ! -d wp-content/mu-plugins ] || printf '%s\n' wp-content/mu-plugins >> "$BACKUP_LIST"
[ ! -f .htaccess ] || printf '%s\n' .htaccess >> "$BACKUP_LIST"
tar czf ~/wp-maint/$(date +%Y%m%d)/code-before-update.tar.gz -T "$BACKUP_LIST"
tar tzf ~/wp-maint/$(date +%Y%m%d)/code-before-update.tar.gz >/dev/null

DBダンプが空でないこと、末尾まで書けていること、コードアーカイブを展開できることを確認する。 ホスティング側のスナップショットを使う場合も、復元手順と保持期限を先に確認する。「取得できた」と「戻せる」は別。

wordpress.org 以外から配布されているプラグイン/テーマは、バージョン指定で再取得できない。 更新対象に含まれる場合、そのディレクトリだけ退避する。

cp -a wp-content/plugins/<slug> ~/wp-maint/$(date +%Y%m%d)/plugins-backup-<slug>

バックアップは認証情報とDBの中身を含む。 公開ディレクトリ配下に置かない。作業後の保管期限を決める。

Step 5. 束に分けて更新する

順序は コア → 中核以外のプラグイン → 中核プラグイン(1つずつ)→ テーマ。 各束のあと、必ずStep 6の確認を挟む。確認せずに次の束へ進まない。

# 束1: コア(マイナーのみに限定したい場合は --minor)
wp core update --minor
wp core update-db

# 束2: 中核以外をまとめて
wp plugin update <slug-a> <slug-b> <slug-c>

# 束3以降: 中核は1つずつ
wp plugin update <core-plugin-slug>

実行の直前に、そのコマンドで何件が変わるかを利用者へ提示して同意を得る。 「まとめて全部お願い」と言われた場合も、束の区切りごとに結果を報告する。

Step 6. 更新後の確認(ここが本体)

HTTPステータスだけを見て「問題なし」と報告しない。200を返したまま壊れる箇所を開く。

wp plugin list --fields=name,status,version --format=csv > plugins-after.csv

# 何が変わったか。プロセス置換 diff <(...) <(...) は bash 専用で、
# レンタルサーバーの /bin/sh(dash)では構文エラーになる。一時ファイルを経由する。
cut -d, -f1,3 plugins-before.csv > before-nv.txt
cut -d, -f1,3 plugins-after.csv  > after-nv.txt
diff before-nv.txt after-nv.txt

wp option get blog_public          # 1 のままか(0 になっていたら検索から消える)
wp core verify-checksums
wp plugin verify-checksums --all

wordpress.org外のプラグインは公式checksumが無く警告になる場合がある。その対象を成功扱いにせず、 更新前ディレクトリとの差分確認または配布元パッケージとの照合を「未確認/別確認」として記録する。

そのうえで、次の6つを実際に開いて確認する。 自動では判定できないので、利用者に確認してもらうか、 確認できていない項目は「未確認」と正直に報告する。

  1. トップページと、下層ページを2〜3枚
  2. 問い合わせフォームの送信(送信して受信箱まで届くか。wp_mail が true でも届かないことがある)
  3. ログイン(管理画面に入れるか。セキュリティ系更新で締め出される事故がある)
  4. ページビルダーの編集画面(Elementor / Divi など。表示は無事でも編集画面だけ壊れることがある)
  5. 決済・カート(ECの場合。テスト注文が通るか)
  6. PHPエラーログ(wp-content/debug.log とサーバーのエラーログに新しい行が出ていないか)

Step 7. WP-CLIが無い場合

管理画面から更新する。記録の取り方だけが変わり、順序は変えない。

  • プラグイン一覧画面で更新前にスクリーンショットを撮るか、名前とバージョンを書き出す。 これが plugins-before.csv の代わりになる。
  • バックアップは事業者の管理画面のバックアップ機能、またはphpMyAdminのエクスポートで取る。 復元手順を先に確認する。 取得だけして復元方法を知らない状態で進まない。
  • 更新は「すべて選択して更新」を使わず、チェックを分けて押す(Step 5の束分けと同じ)。
  • 戻すときは、旧バージョンのzipを取得して手動アップロードする(ROLLBACK.md 参照)。

Step 8. 記録を残す

保守は「やったこと」ではなく「戻せること」と「変わったこと」が資産になる。

{
  echo "## 更新日: $(date +%Y-%m-%d)"
  echo "### 変更されたもの"
  diff before-nv.txt after-nv.txt        # Step 6 で作った一時ファイルを使う
  echo "### 確認した項目と結果"
} > "report-$WORKDATE.md"

未確認の項目は未確認と書く。 確認していないものを「問題なし」と書かない。


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

  1. バックアップが取得できない、または復元方法が確認できない。
  2. 「全部まとめて上げて。確認は要らない」と、束の区切りごとの報告を省くよう求められた。 包括的な事前同意は「方針への同意」であって「個々の破壊的操作への白紙委任」ではない。 更新を実行する直前には、その束で何が変わるかを毎回提示する。
  3. 更新対象に、wordpress.org 以外から配布されていて戻す手段が確保できないものが含まれる。
  4. 型がM3(長期停滞)で、ステージング環境が無い。
  5. サイトがECまたは会員制で、営業時間中に作業を求められた。
  6. すでに壊れている状態で、原因調査を先に求められた(M4では戻すのが先)。
  7. 依頼者がそのサイトの管理権限を持っているか確認できない。

このSkillが行わないこと

  • サーバー契約、DNS変更、決済設定の変更
  • PHPバージョンの更新(更新作業と同時に行わない。別作業として分ける)
  • 脆弱性データベースの同梱。緊急更新ではWordPress公式・配布元・公的脆弱性情報を都度確認する
  • 自動更新の常時有効化の推奨(サイトの性質によって是非が変わるため、判断材料だけ出す)

詳細手順