タグアーカイブ WordPress

WordPress 7.0.2リリース、SQLインジェクションとRCEの深刻な脆弱性を修正

WordPress 7.0.2リリース、SQLインジェクションとRCEの深刻な脆弱性を修正

WordPress 7.0.2が2026年7月17日にリリースされた。今回のアップデートは深刻度「クリティカル」1件と「高」1件、計2件のセキュリティ脆弱性を修正する緊急リリースだ。

対象となる脆弱性は悪用されればサイトの完全掌握につながる可能性がある。WordPress.orgは影響を受ける全サイトに対し、自動更新システムを通じた強制アップデートを有効化した。手動更新も含め、即座の対応が強く推奨される。

この記事では脆弱性の詳細、影響を受けるバージョン、具体的な更新手順を整理する。サイト管理者はまず自サイトのバージョンを確認し、該当する場合は今すぐアップデートを実行してほしい。

修正された2件の脆弱性の概要

修正された2件の脆弱性の概要

WordPress 7.0.2では、SQLインジェクションとREST API経由のリモートコード実行(RCE)という2件の深刻な問題が修正された。いずれも攻撃者にサイトの内部データへの不正アクセスや、サーバー上での任意コード実行を許す可能性がある。

SQLインジェクションの脆弱性

1件目はSQLインジェクションの脆弱性だ。SQLインジェクションとは、Webアプリケーションがデータベースに送るSQL文(問い合わせ命令)に、攻撃者が不正な文字列を紛れ込ませる攻撃手法を指す。これが成功すると、データベース内の情報を盗み見られたり、データを改ざんされたりする。

今回の脆弱性はTF1T、dtro、haongoの3名によるチーム報告で発見された。WordPressの内部処理で、特定の条件下においてSQLクエリが適切にサニタイズ(無害化)されず、攻撃者が細工した入力を通じてデータベース操作を実行できる状態になっていた。

脆弱な状態(修正前)
攻撃者 細工した入力 WordPress
危険: SQL文に不正な文字列が混入 → データベースの情報漏洩や改ざんが発生
※入力値のサニタイズが不十分な箇所を攻撃者が突く
修正後の状態(7.0.2)
ユーザー入力 エスケープ処理 WordPress
安全: 特殊文字はすべて無害化され、SQL文として解釈されない

上の図は、修正前後での入力処理の違いを示している。修正前は攻撃者の細工した文字列がそのままSQL文に渡っていたが、修正後はエスケープ処理によって危険な文字が無害化される。

REST API経由のRCE脆弱性

2件目はさらに深刻だ。REST APIのバッチルートの混乱とSQLインジェクションが組み合わさり、リモートコード実行(RCE)に至る脆弱性である。RCEとは、攻撃者が遠隔からサーバー上で任意のプログラムコードを実行できる状態を指す。サイトの完全な乗っ取りが可能になる、最悪のシナリオだ。

REST APIとは、WordPressが外部アプリケーションとのデータ送受信に使うインターフェースである。バッチルートは複数のAPIリクエストを1回でまとめて処理する仕組みで、ここにリクエスト経路の混乱(どのエンドポイントが処理すべきかの取り違え)が発生していた。

この脆弱性はAssetnote / Searchlight Cyber所属のAdam Kues氏によって報告された。REST APIのバッチ処理で生じる経路混乱を起点にSQLインジェクションを発生させ、最終的にサーバー上でのコード実行につなげる攻撃チェーンが成立していた。

攻撃チェーンの流れ(修正前)
STEP 1 攻撃者が細工したバッチリクエストをREST APIに送信
STEP 2 バッチルートの混乱により想定外のエンドポイントで処理
STEP 3 SQLインジェクションが成立しデータベースを操作
STEP 4 サーバー上で任意コード実行(RCE)→ サイト完全掌握
結果: サイトのデータ流出・改ざん・マルウェア設置が可能な状態
修正後の状態(7.0.2)
安全: バッチルートの経路検証が強化され、想定外のエンドポイント呼び出しをブロック。SQLクエリも適切にエスケープ処理される

この攻撃チェーンは多段階で構成される。REST APIのバッチ処理を入り口に、経路混乱→SQLインジェクション→RCEという流れでサーバーへの侵入を許していた。7.0.2では各段階の根本原因が修正されている。

影響を受けるバージョンとバックポート

影響を受けるバージョンとバックポート

WordPress 7.0.2のリリースと同時に、複数の旧バージョン向けバックポート(修正の遡及適用)も公開されている。現在運用中のサイトがどのバージョンに該当するか、以下の一覧で確認してほしい。

バージョン別の影響と修正状況
WordPress 7.0 / 7.0.1 両方の脆弱性の影響あり → 7.0.2 へ更新
WordPress 7.1 Beta 1 両方の脆弱性の影響あり → 7.1 Beta 2 へ更新
WordPress 6.9 両方の脆弱性の影響あり → 6.9.5 へ更新
WordPress 6.8 1件目の脆弱性のみ影響あり → 6.8.6 へ更新
WordPress 6.7 以前 両方の脆弱性の影響なし(更新不要だが最新版への更新を推奨)

6.8系はREST API経由のRCE脆弱性の影響を受けない点が救いだが、SQLインジェクションのリスクは残る。6.8.6への更新は必須だ。6.9系と7.0系、および7.1ベータは両方の脆弱性の影響を受けるため、対応バージョンへの即時更新が求められる。

今すぐ実行すべきアップデート手順

今すぐ実行すべきアップデート手順

WordPress 7.0.2はセキュリティリリースのため、WordPress.orgが自動更新システムを通じた強制アップデートを有効化している。自動バックグラウンド更新に対応しているサイトでは、すでに更新が始まっているはずだ。

管理画面からの手動更新

自動更新が動作していない環境や、今すぐ手動で更新したい場合は以下の手順で対応する。

手動アップデートの手順
STEP 1 WordPress管理画面にログインする
STEP 2 ダッシュボード → 更新 をクリックする
STEP 3 「WordPress 7.0.2が利用可能です」の表示を確認する
STEP 4 「今すぐ更新」をクリックして完了を待つ
推奨: 更新前に必ずサイト全体のバックアップを取得すること

上記の手順で数分以内に更新は完了する。更新後はサイトの表示や主要機能が正常に動作することを必ず確認してほしい。プラグインとの互換性問題が発生した場合は、プラグイン側のアップデート有無も合わせてチェックするとよい。

手動ダウンロードとFTP更新

何らかの理由で管理画面から更新できない場合は、WordPress.orgからZIPファイルを直接ダウンロードし、FTP/SFTPでサーバーにアップロードする方法もある。この方法はファイルの上書きミスによるサイト停止リスクを伴うため、可能な限り管理画面からの更新を推奨する。

セキュリティリリースの背景と教訓

セキュリティリリースの背景と教訓

今回の2件の脆弱性に共通するのは入力値の検証不足APIエンドポイントの経路管理の不備である。いずれもWebアプリケーション全般に共通する古典的な脆弱性パターンだが、WordPressほどの巨大プロジェクトでも発生しうるという事実は重い。

REST APIのセキュリティと運用上の注意

REST APIはWordPress 4.7で導入されて以来、外部サービス連携やヘッドレスCMS構成に不可欠な存在となっている。一方で、APIエンドポイントが増えるほど攻撃対象領域(アタックサーフェス)も広がる。今回のバッチルート問題は、複雑なAPI設計に潜むリスクを浮き彫りにした。

サイト管理者として取れる対策は限られているが、最低限以下の運用を徹底したい。

  • WordPress本体および全プラグインを常に最新バージョンに保つ
  • 使用していないREST APIエンドポイントは必要に応じて無効化する
  • WAF(Webアプリケーションファイアウォール)の導入を検討する
  • 定期的なセキュリティ監査とログ監視を実施する

WordPress.orgの強制自動更新は両刃の剣

今回、WordPress.orgは深刻度の高さを理由に強制自動更新を有効化した。この判断は「脆弱性が悪用される前に全サイトを保護する」という観点では合理的だが、自動更新によってサイトが意図せず停止するリスクもゼロではない。

特にカスタム開発の多いサイトや、互換性テストを経ていないプラグインを多数導入している環境では、更新後の動作確認が必須だ。自動更新はセキュリティ上の「最後の砦」として機能するが、日頃から更新適用前のテスト環境を用意しておくことが理想である。

この記事のポイント

  • WordPress 7.0.2は深刻度「クリティカル」と「高」の脆弱性2件を修正する緊急セキュリティリリース
  • SQLインジェクションとREST API経由のRCEが修正対象。悪用されればサイトの完全掌握が可能
  • WordPress 6.8〜7.1 Beta 1が影響を受ける。各バージョン向けのバックポートが同時公開された
  • WordPress.orgが強制自動更新を有効化済み。手動更新は管理画面の「更新」から即座に実行できる
  • 更新前のバックアップ取得と更新後の動作確認は必須。日頃からのテスト環境整備が被害を防ぐ
Booking Calendar更新後にサイトが壊れた時の原因と直し方

Booking Calendar更新後にサイトが壊れた時の原因と直し方

Booking Calendar プラグインを 11.4.1 から 11.4.2 へ更新した直後にサイトが壊れた場合、無料版(Booking Calendar)と有料版(Booking Calendar Pro または Booking Manager)のバージョン不一致が主要因だ。手動で両方を同一の最新バージョンに揃え、かつ Pro 版のライセンスを再適用すれば復旧できる。

なぜバージョン 11.4.2 への更新でサイトが壊れたのか

なぜバージョン 11.4.2 への更新でサイトが壊れたのか

Booking Calendar は無料版(WordPress.org 配布)と、追加機能を提供する Pro 版(開発元サイトで購入)が連携して動作する設計になっている。無料版は管理画面の「プラグイン」から自動更新される一方、Pro 版は手動で更新する必要がある。両者のバージョンが食い違うと、共有する関数やデータベース構造に不整合が生じ、PHP の致命的エラーを引き起こして画面が表示されなくなる。

とくに 11.4.2 では内部 API の変更が加えられており、Pro 版が旧バージョンのまま無料版だけを更新すると競合が起きやすい。この状態で WordPress の「このサイトで重大なエラーが発生しました」というメッセージが表示されたり、管理画面にアクセスできなくなったりする。

サイトを元に戻す具体的な手順

サイトを元に戻す具体的な手順

以下の手順で、無料版と Pro 版を安全に最新へ揃える。作業前に必ずサイト全体のバックアップを取得しておく。

STEP 1 FTP またはホスティングのファイルマネージャで /wp-content/plugins/ にアクセスする
STEP 2 無料版と Pro 版の両方のフォルダを一時的にリネームして無効化する(例: bookingbooking_old
STEP 3 無料版を WordPress.org から最新版(11.4.2)で再インストールし有効化する
STEP 4 開発元サイトから Pro 版の最新をダウンロードし、管理画面からアップロードして有効化、ライセンスキーを再入力する

プラグインフォルダを特定して無効化する

サイトが壊れて管理画面に入れない場合は、FTP(File Transfer Protocol)クライアントやレンタルサーバーのファイルマネージャを使う。/wp-content/plugins/ ディレクトリ内に、無料版(通常は booking または booking-calendar)と Pro 版(booking-calendar-prowpdev-booking など)のフォルダが存在する。両方をリネームすれば、WordPress はプラグインを強制的に無効化し、サイトが最低限の状態で表示されるようになる。リネーム後のフォルダ名は削除せず控えておく。

無料版を最新にして Pro 版を再適用する

管理画面にアクセスできる状態になったら、プラグイン一覧画面で一度 Booking Calendar を削除する。削除しても予約データはデータベースに保持されるため、消えることはない。その後「新規追加」から再度 Booking Calendar 11.4.2 をインストールし有効化する。

続いて開発元サイト(wpbookingcalendar.com)のアカウントページから、無料版と同一バージョン(11.4.2)に対応した Pro 版の ZIP ファイルをダウンロードする。管理画面の「プラグイン」→「新規追加」→「プラグインのアップロード」から ZIP を投入し、有効化後にライセンスキーを入力すれば復旧が完了する。Pro 版の最新ファイルが入手できない場合は、開発元のサポートへ直接更新ファイルを依頼する。

どうしても復旧できない場合の最終手段

Pro 版の最新 ZIP が手元になく、サイトのダウンタイムが許容できない状況では、無料版を旧バージョン(11.4.1)にダウングレードする選択肢もある。WordPress.org のプラグインページにある「以前のバージョン」から 11.4.1 の ZIP を入手し、FTP で手動上書きすれば以前の動作に戻せる。ただしセキュリティ修正が含まれている可能性があるため、この状態は恒久的な対策にはならず、早期に Pro 版を最新化する必要がある。

再発を防ぐための運用ルール

再発を防ぐための運用ルール

Booking Calendar のように無料版と有料版が連動するプラグインは、無料版の自動更新をオフにするか、更新前に必ず Pro 版の対応バージョンがリリースされているかを確認する習慣をつける。開発元のチェンジログやメーリングリストを購読しておくと、更新のタイミングを逃さない。

また本番環境に直接適用する前に、ステージング環境(本番と同一構成のテストサイト)で無料版と Pro 版の同時更新を試すのが最も確実な予防策になる。レンタルサーバーのステージング機能を使うか、WP Staging のようなプラグインで簡易的なテスト環境を用意できる。

よくある質問

Pro 版の最新ファイルがアカウントページに見当たらない場合はどうすればよいか

開発元の公式サイトにある問い合わせフォームまたはサポートチケットから、Pro 版の最新 ZIP ファイルを直接依頼する。購入時のメールアドレスやライセンスキーを記載すれば、通常は数営業日以内にダウンロードリンクが提供される。

フォルダをリネームしたがサイトがまだ壊れている

キャッシュ系プラグインや CDN(コンテンツデリバリネットワーク / 配信網)が古いエラー画面を配信し続けている可能性がある。サーバー側のキャッシュをすべてクリアし、ブラウザのシークレットモードで確認する。また wp-content/mu-plugins/ に手動で入れたファイルが競合していないかも調べる。

ライセンスキーを入力しても Pro 版の機能が有効にならない

ライセンスキーが旧バージョン向けのまま失効している可能性がある。開発元のマイページでキーを再発行するか、サポートにキーのリセットを依頼する。ドメインを変更した場合もライセンスの再割り当てが必要になる場合がある。

この記事のポイント

  • Booking Calendar 11.4.1 から 11.4.2 への更新障害は無料版と Pro 版のバージョン競合が原因
  • FTP で両方のプラグインフォルダをリネームし強制無効化して管理画面へ復帰
  • 無料版は削除後に 11.4.2 を再インストール、Pro 版は開発元から同一バージョンを入手
  • Pro 版がすぐ用意できない場合は無料版のみ旧バージョン 11.4.1 に戻す応急処置も可能
  • 再発防止には無料版の自動更新を止め、Pro 版のリリース確認後に揃えて更新する
WordPressをサブフォルダにインストールするとREST APIが404になる原因と直し方

WordPressをサブフォルダにインストールするとREST APIが404になる原因と直し方

WordPressをサブフォルダにインストールしている環境で、REST APIのエンドポイントが404エラーを返す場合は、プラグインがサブフォルダを考慮せずにAPIのURLを生成しているバグが原因だ。該当プラグインを最新版に更新するか、パーマリンク設定のリフレッシュで解決する。

なぜサブフォルダ環境でプラグインのAPIが404になるのか

なぜサブフォルダ環境でプラグインのAPIが404になるのか

WordPressをドキュメントルート直下ではなく/blog/siteのようなサブフォルダにインストールした場合、REST APIのベースURLはhttps://example.com/subfolder/wp-json/となる必要がある。ところが一部のプラグインは、内部でAPIのURLを組み立てる際にこのサブフォルダを考慮しておらず、https://example.com/wp-json/...のようにルート直下を指してしまう。その結果、実在しないパスへのリクエストとなり404が返る。

今回のケースでは、プラグインが独自に追加したエンドポイント/profeedwp/v1/linkedin/company-posts/smartに対して、サブフォルダを含まない不完全なURLでリクエストを発行していた。同様の問題は、テーマや他のプラグインがrest_url()関数を正しく使わずにハードコードしたパスを参照している場合にも起こる。

解決手順

解決手順

まず簡単かつ即効性のある方法として、問題のプラグインを最新版へ更新する。次に、WordPressのパーマリンク設定をリセットし、REST APIのルートURLが正しく再構築されるか確認する。これで直らない場合は、手動でrest_url()が返す値を検証し、他のプラグインとの競合を調べる。

STEP 1 問題のプラグインを最新版に更新する
STEP 2 パーマリンク設定をリセットして API ルートを再構築する
STEP 3 rest_url() の戻り値を検証し、サブフォルダが含まれるか確認する
STEP 4 全プラグインを無効化して競合を切り分ける

プラグインを最新版に更新する

本件ではバージョン1.6.10で修正が行われている。管理画面の「プラグイン」→「インストール済みプラグイン」から対象プラグインを確認し、更新が表示されていれば適用する。更新が出ていない場合は、一度プラグインを削除して再インストールするか、開発元の公式ページから修正版がリリースされていないか確認する。

パーマリンク設定をリセットする

プラグインの更新で直らなかった場合、パーマリンク構造の再保存でWordPress内部のルーティングをリフレッシュできる。「設定」→「パーマリンク」を開き、現在選択されている設定をそのままの状態で「変更を保存」をクリックする。これにより.htaccessの再生成と、REST APIのルート定義が再構築される。サブフォルダ環境では特に、リライトルールが正しくサブフォルダをプレフィックスとして含む必要があるため、この一手順で解決するケースが多い。

rest_url() の戻り値を検証する

根本原因がプラグイン側のURL組み立てにあるかどうかを切り分けるには、WordPressが正しいREST APIのルートURLを返しているかを確認する。テーマのfunctions.phpなどに次のようなテストコードを一時的に追加する。

add_action('wp_footer', function() {
    echo '<!-- REST URL: ' . esc_url(rest_url()) . ' -->';
});

サイトのフッター部分のHTMLソースに出力されたURLがhttps://example.com/subfolder/wp-json/の形式になっていれば、WordPress本体の認識は正しい。もし/subfolderが欠落している場合は、wp-config.phpWP_HOMEWP_SITEURLが正しくサブフォルダを含んだ値で定義されているか確認する。

全プラグインを無効化して競合を切り分ける

それでも404が解消しない場合、別のプラグインがREST APIのルーティングに干渉している可能性がある。すべてのプラグインを一括で無効化し、問題のエンドポイントにアクセスして200番台のレスポンスが返るかテストする。正常動作が確認できたら、プラグインを1つずつ有効化して原因のプラグインを特定する。キャッシュ系プラグインやセキュリティプラグインは、REST APIへのリクエストをブロックしたり、URLを書き換えたりする設定項目を持つことがあるため、該当するプラグインの設定もあわせて確認する。

よくある質問

サブフォルダにインストールする際にwp-config.phpで注意すべき点は?

WP_HOMEWP_SITEURLの定数をhttps://example.com/subfolderのようにサブフォルダを含めて明示的に定義しておくと、サイトURLの誤認識を防げる。wp-config.phpに記述しなければならないわけではないが、マルチサーバー構成やリバースプロキシの背後で運用する場合は特に有効だ。

REST APIの404エラーはどのようにデバッグすればいいか?

ブラウザのデベロッパーツールのネットワークタブで、実際に送信されたリクエストURLを確認する。サブフォルダが欠落したURLでリクエストが発生している場合は、呼び出し元のJavaScriptファイルやPHPコードでURLの組み立て方をチェックする。rest_url()を使わずにハードコードされたパスが原因であることが多い。

プラグインを更新しても問題が再発する場合は?

修正パッチが適用されたバージョンでも、キャッシュの残存やデータベースに保存された古い設定値が原因で再発することがある。プラグインを完全に削除したあと、wp_optionsテーブルに残っている該当プラグインのオプションを手動で削除し、最新版を再インストールすると改善する場合がある。

サブフォルダ環境でなくてもAPIが404になる原因は?

パーマリンク設定が「基本」になっているとREST APIが動作しない。また、セキュリティプラグインが/wp-json/へのアクセスを制限しているケースもある。.htaccessのリライトルールが破損している場合も404になるため、パーマリンク設定の再保存でリフレッシュするのが初手として有効だ。

この記事のポイント

  • サブフォルダ環境でプラグインのAPIが404になるのは、URLにサブフォルダが含まれない不完全なパスが原因
  • 問題のプラグインを最新版に更新し、パーマリンク設定を再保存するのが解決の基本手順
  • rest_url() の戻り値とwp-config.phpの設定を確認し、WordPress本体のURL認識が正しいか検証する
  • 全プラグインの無効化で競合を切り分け、キャッシュやセキュリティ系プラグインの干渉を疑う
WP-CLIとREST APIとAbilities API、WordPressインターフェースの選び方

WP-CLIとREST APIとAbilities API、WordPressインターフェースの選び方

3つのインターフェースの全体像

3つのインターフェースの全体像

WordPressには外部からデータをやり取りするための主要なインターフェースが3つ存在する。WP-CLI、REST API、Abilities APIだ。それぞれが異なる距離感でWordPressと向き合い、異なる呼び出し元に対応する。これらを競合関係と捉えるのは誤りで、実際には階層構造をなしている。

WP-CLIはサーバー上で動作し、REST APIはHTTPを介して通信する。そしてAbilities APIは、そのさらに上位に位置し、AIエージェントが何をすべきかを判断する層になる。どのレイヤーがどこに位置するのかを理解すれば、タスクに応じた最適な選択はおのずと見えてくる。

  • WP-CLI:サーバー上で直接PHPを実行(またはSSH経由)。一括操作、移行、デプロイ、メンテナンス向き
  • REST API:wp-jsonへのHTTPリクエスト。ブラウザ、モバイルアプリ、外部サービスからコンテンツの読み書きに使用
  • Abilities API:RESTとMCPで公開される名前付きPHPケイパビリティ。AIエージェントが安全に操作を行えるように設計
Abilities API(AIエージェント層)
AIエージェントが安全にWordPressを操作するためのケイパビリティ定義
「何ができるか」を記述し、許可された操作のみを公開する
REST API(HTTP層)
ブラウザ、アプリ、外部サービスからのHTTP通信
「どんなデータがあるか」を公開し、認証付きで読み書き可能に
WP-CLI(コマンドライン層)
サーバー上での直接PHP実行、SSH経由の一括操作
HTTP往復なし、認証トークン不要、最高速での実行が可能
■ 上位層ほど「自律性」が高く「説明的」 ■ 下位層ほど「高速」で「直接操作」

3つのインターフェースは、下位ほど呼び出し元がサイトに近く、信頼度も高い。上位になるほど、呼び出し元は自律的で遠隔地に位置する。この構造を理解すれば、「どれを使うべきか」の判断はシンプルになる。

WP-CLI:サーバー上のコマンドライン

WP-CLI:サーバー上のコマンドライン

WP-CLIはWordPressのインストール環境に対して直接PHPを実行する。コマンド例としては wp post createwp plugin updatewp search-replacewp db export などがある。実行にはサーバーへのシェルアクセス(SSH)が前提だが、その分HTTPの往復も認証トークンの管理も不要になる。

WP-CLIが最も威力を発揮するのは、サイトを完全に制御できる状況だ。1000件の投稿を移行する、データベース全体でドメインを置換する、定期メンテナンスをスクリプト化する、あるいはデプロイの自動化など、スピードが求められる一括操作では他の追随を許さない。

WP-CLIが適さないケース
ブラウザやモバイルアプリからのアクセス、リモートサービスとの連携には使えない
WP-CLIが最も輝く場面
一括移行、データベース操作、定期メンテナンスの自動化、デプロイスクリプト

WP-CLIはシェルアクセスが前提のため、ブラウザやモバイルアプリ、外部サービスがサイトと通信する手段にはなりえない。しかし開発者がサイト全体を制御できる状況では、WP-CLIは圧倒的な速度と柔軟性を提供する。ターミナルからすべてを操作するワークフローが浸透している開発現場も多く、管理画面(wp-admin)をほとんど開かない運用も可能だ。

REST API:HTTP越しのWordPress

REST API:HTTP越しのWordPress

REST APIはWordPressサイトを、あらゆるHTTPクライアントが読み書きできる状態に変換する。エンドポイントは /wp-json/wp/v2/ 配下に存在し、認証にはアプリケーションパスワード、Cookieとnonce、あるいはOAuthを用いる。ブラウザ、モバイルアプリ、外部サービスがインターネット越しにコンテンツを取得・更新できるようになる。

ヘッドレスCMS構成のWordPressは、このREST APIを基盤に動作する。AstroやNext.jsで構築したフロントエンドがREST経由でコンテンツを取得し、モバイルアプリが投稿を行い、サードパーティ連携がデータを同期する。呼び出し元がサーバー外にいる場合、REST APIがほぼ唯一の通信経路となる。

REST APIの構造と制約
公開するもの
投稿、ユーザー、タクソノミー、設定といった「リソース」
公開しないもの
「誰が何をしたいのか」という意図や操作の文脈
人間の開発者ならドキュメントを読んで適切なリクエストを組み立てられるが、AIエージェントにはハードルが高い

REST APIには重要な限界がある。公開するのは「データの構造」であり、「そのデータで何をしたいのか」という操作の意図までは記述しない。どのエンドポイントが存在し、どうリクエストを組み立てるべきかは、呼び出し元が自ら理解する必要がある。人間の開発者であれば問題ないが、AIエージェントにとっては推論すべき情報が多すぎるという課題が残る。

Abilities API:AIエージェントのためのケイパビリティ層

Abilities API:AIエージェントのためのケイパビリティ層

Abilities APIはWordPress 6.9でコアに導入された最新のインターフェースだ(それ以前のバージョン向けにはプラグインも提供されている)。REST APIが残した「AIエージェントが何を許可されているのかをどう知るか」という課題を解決するために設計された。

Abilities APIでは、生のリソースを公開する代わりに、プラグインやテーマが「名前付きケイパビリティ(能力)」を登録する。各アビリティは、一意のID、人間が読めるラベル、説明文、入力・出力のスキーマ、権限チェックのコールバック、そして実行コールバックを備えた独立した操作単位となる。

add_action( 'wp_abilities_api_init', function () {
    wp_register_ability( 'my-plugin/publish-draft', [
        'label'             => '下書きを公開',
        'description'       => 'IDを指定して既存の下書き投稿を公開する',
        'category'          => 'my-plugin',
        'input_schema'      => [ /* 期待する入力のJSON Schema */ ],
        'output_schema'     => [ /* 結果のJSON Schema */ ],
        'permission_callback' => 'my_plugin_can_publish',
        'execute_callback'  => 'my_plugin_publish_draft',
        'meta'              => [ 'show_in_rest' => true ],
    ] );
} );
REST API
データの構造を公開する
「どんなリソースがあるか」に答える
Abilities API
操作の意図と許可を公開する
「何ができるか」「誰が許可されているか」に答える
アビリティは「これが実行可能な操作であり、必要な入力と許可条件はこれだ」という契約をAIエージェントに提示する

meta.show_in_rest をtrueに設定すると、そのアビリティは wp-json/wp-abilities/v1/abilities で公開され、クライアントが検出できるようになる。JavaScript側では @wordpress/abilities パッケージを介して利用する。

Abilities APIの最大の価値は、エージェントが安全に行動するために必要な「契約」を提供することだ。操作の定義、必要な入力形式、実行許可の条件が明示されるため、AIエージェントがサイトを壊すリスクを最小限に抑えられる。複数のエージェントが共通の語彙で協調動作するマルチエージェント構成でも、Abilities APIが基盤になりつつある。

3つのインターフェースの積み重なり方

3つのインターフェースの積み重なり方

3つのインターフェースは互いに積み重なる関係にある。Abilities APIは多くの場合REST APIの上に構築され、REST APIはWP-CLIが直接駆動するPHPの上で動作する。すべての基盤にあるのは、同じWordPressコア、同じデータベース、同じ関数群だ。

したがって問うべきは「どれが最善か」ではない。「呼び出し元がサイトからどれだけ離れているか」「操作の意図をどこまで明示する必要があるか」という視点で選択することが本質になる。呼び出し元が近く信頼できるほど下位層を、自律的で遠隔にあるほど上位層を使う。

距離:最短 サーバー上(SSH) WP-CLI 一括操作・最高速
距離:中程度 HTTP越し(リモート) REST API データの読み書き
距離:最長 AIエージェント(自律的) Abilities API 安全な操作定義

上位層になるほど「記述性」と「安全性」が重視され、下位層ほど「速度」と「直接制御」に優れる。これらは設計上、相補的な関係にあり、実際のプロジェクトではすべてを併用するのが理想的な構成だ。

各インターフェースの使い分け方

各インターフェースの使い分け方

日常的なタスクにおける選択指針を整理する。

  • 自分が制御するサイトに対して、一括かつ高速に操作したい → WP-CLI。移行、デプロイ、定期ジョブ、データベース操作が該当する
  • ブラウザ、アプリ、外部サービスがコンテンツを読み書きする必要がある → REST API。ヘッドレスフロントエンド、モバイルアプリ、外部連携が該当する
  • AIエージェントにサイトを壊さず操作させたい → Abilities API。許可したい操作をスキーマと権限付きで登録し、エージェントに発見させる
STEP 1 呼び出し元の「距離」を確認する(サーバー内か、リモートか、自律エージェントか)
STEP 2 操作に必要な「明示性」を判断する(データ構造だけで足りるか、操作意図の記述が必要か)
STEP 3 最適なレイヤーを選ぶ(多くの場合、複数レイヤーの併用が正解)

実際のプロジェクトでは、この3つを排他的に使うことはまれだ。むしろそれぞれの得意領域を活かして組み合わせるのが、効率的なWordPress運用の鍵になる。

3つを組み合わせた実践的な構成

3つを組み合わせた実践的な構成

WP Mayorの記事では、実際に3つのインターフェースを併用している構成例が紹介されている。まず、公開運用と日常的な運用作業はSSH経由のWP-CLIで実行される。新規投稿、メディアのインポート、プラグイン更新、キャッシュクリアといった操作をターミナルから完結させ、管理画面(wp-admin)をほとんど開かない運用が行われている。

フロントエンドはヘッドレス構成で、REST API越しにコンテンツを取得する。Astroで構築されたサイトが wp-json 経由でWordPressからデータを取得し、高速な静的ページとして配信する。訪問者はWordPressテーマに触れることなく、WordPressはバックエンドのエンジンとして機能し、REST APIがそのパイプ役を担う。

エージェント向けの機能はAbilities APIを通じて提供される。AIエージェントに限定的なタスクを任せたい場合、関連プラグインがその操作をアビリティとして登録する。権限チェックとスキーマを伴うため、シェルアクセスを丸ごと渡したり、大量の生エンドポイントをエージェントに解析させたりする必要がなくなる。

WP-CLI(運用層)
投稿・メディア・プラグイン管理をターミナルから一括実行。シェルアクセス可能なAIアシスタントも直接駆動できる
REST API(配信層)
ヘッドレスフロントエンドがコンテンツを取得。Astroが静的ページとして配信し、訪問者はWordPressテーマに触れない
Abilities API(エージェント層)
AIエージェント向けにスコープ付き操作を登録。権限チェックとスキーマにより安全な自動化を実現
各レイヤーがそれぞれの得意領域を担当し、互いに補完し合う構成

WP-CLIは速度と一括処理能力で、REST APIは外部連携の柔軟性で、Abilities APIはAIエージェントの安全性で優位性を持つ。1つのインターフェースに別の役割を強制しようとするところから問題は始まる。3つのレイヤーを適材適所で使い分けることが、WordPress自動化の効率を最大化する道筋だ。

この記事のポイント

  • WP-CLI、REST API、Abilities APIは競合ではなく、呼び出し元の距離に応じた階層構造をなす
  • WP-CLIはサーバー上の直接操作に最適で、一括処理と速度が求められる場面で選ぶ
  • REST APIはHTTP越しのデータ読み書きを担い、ヘッドレス構成やモバイルアプリ連携の基盤となる
  • Abilities APIはAIエージェントに操作の安全な契約を提供し、マルチエージェント構成でも威力を発揮する
  • 実際のプロジェクトでは3つを組み合わせ、各レイヤーの得意領域を活かすのが理想的な運用だ
Gravity Forms PDFで合計金額が倍になる原因と修正方法

Gravity Forms PDFで合計金額が倍になる原因と修正方法

Gravity Forms で作成したフォームから PDF を出力するプラグイン「PDF Invoices for Gravity Forms」を使っていて、テンプレート内で get_total() メソッドを複数回呼び出すと合計金額が呼び出し回数に応じて倍々に膨らんでしまう現象は、静的変数 self::$total が各呼び出しのたびに加算され続ける設計になっているのが原因だ。直すにはヘルパークラスを子テーマから拡張し、get_total() の内部で毎回リセットして再計算させる変更を加える。

合計金額が倍になる現象はどのようなときに起こるのか

合計金額が倍になる現象はどのようなときに起こるのか

たとえば請求書のテンプレートに「小計」と「総合計」を別々の位置に表示したい場合、PDF_Invoices_For_GravityForms_Helpers::get_total() を2回呼ぶことになる。ところがイベント参加登録や商品注文フォームなどで実際にこの処理を通すと、2回目の呼び出し時には1回目に加算された値にさらに同じ計算が上乗せされ、本来 10,000 円のところが 20,000 円になるといった不具合が起きる。

なぜ get_total() を複数回呼ぶと値が積み上がるのか

なぜ get_total() を複数回呼ぶと値が積み上がるのか

問題の根本は class-pcafe-gfpi-helpers.php ファイル内の get_total() メソッドにある。このメソッドは静的変数 self::$total を使い、内部で次のように加算している。

public static function get_total(){
    self::$total += self::get_subtotal();
    self::$total += self::$shipping;
    return self::$total;
}

静的変数はリクエストの間ずっと値を保持するため、同じ処理中に get_total() が呼ばれるたびに前回の合計に小計と送料が足されていく。2回呼べば「小計 + 送料」が2倍になり、3回なら3倍になる。通常、こうした合計取得メソッドは毎回ゼロから計算し直すべきであり、内部で継ぎ足す構造は意図したものでない可能性が高い。

Before(問題のある状態)
1回目呼び出し: 小計=10,000 + 送料=500 → total=10,500
変数 self::$total が 10,500 を保持したまま
2回目呼び出し: 10,500 + 10,000 + 500 → total=21,000
After(修正後のあるべき動作)
1回目呼び出し: 小計=10,000 + 送料=500 → total=10,500
2回目呼び出し: 変数をリセット後 再計算 → total=10,500
静的変数が保持され加算される問題  毎回リセットして再計算する修正後

上の図のように、2回目で合計が倍になる。特に「小計」「消費税」「総合計」など複数の金額を PDF テンプレートに配置する場合にこの問題が顕在化しやすい。

get_total() 修正の基本的な考え方

get_total() 修正の基本的な考え方

プラグイン本体のファイルを直接編集してしまうと、アップデートのたびに修正が上書きされて消える。そのため子テーマの functions.php を使い、プラグインのヘルパークラスを拡張した独自クラスを用意する方法をとる。拡張クラスでは get_total() メソッドをオーバーライドし、計算前に self::$total を強制的に 0 にリセットしてから小計と送料を加算する。

子テーマでヘルパークラスを拡張して修正する手順

子テーマでヘルパークラスを拡張して修正する手順

独自ヘルパークラスを作成する

まず子テーマの functions.php に、プラグインのヘルパークラスを継承したクラスを定義する。子テーマがない場合は、Code Snippets プラグインを使うか、wp-content/themes/(現在のテーマ)/functions.php に追記する形でもよい。コードは以下のようになる。

class Custom_GFPI_Helpers extends PDF_Invoices_For_GravityForms_Helpers {

    public static function get_total() {
        self::$total = 0; // 計算前に必ずリセットする
        self::$total += self::get_subtotal();
        self::$total += self::$shipping;
        return self::$total;
    }
}

テンプレート内でカスタムクラスを呼び出す

拡張クラスを作っただけでは既存のテンプレートには反映されない。PDF テンプレート内で PDF_Invoices_For_GravityForms_Helpers::get_total() を呼んでいる箇所を、先ほど定義した Custom_GFPI_Helpers::get_total() に置き換える。

テンプレートファイルは多くの場合 wp-content/uploads/pdf-invoices-for-gravity-forms/templates/ 以下にカスタムテンプレートとして配置されている。該当の .php ファイルを開き、以下のように書き換える。

<?php
// 修正前
// echo PDF_Invoices_For_GravityForms_Helpers::get_total();

// 修正後
echo Custom_GFPI_Helpers::get_total();
?>

これでテンプレート内のどの場所から呼び出しても、毎回リセット後に計算が走るため合計が積み上がることはなくなる。

変更後にキャッシュと動作を確認する

変更を加えたあとは、必ず PDF を生成し直して合計金額が正しいか確認する。Gravity Forms のエントリーから「PDFを表示」ボタンで実際の請求書を開き、同じ合計が要求された位置すべてに正しく表示されているかをチェックする。サイトでキャッシュプラグインを使っている場合は、キャッシュを全削除してから確認すると確実だ。

STEP 1 子テーマの functions.php にカスタムクラスを定義する
STEP 2 PDF テンプレート内の呼び出しを Custom_GFPI_Helpers に変更する
STEP 3 キャッシュを削除し、PDF を生成し直して合計金額を確認する

よくある質問

プラグイン本体のファイルを直接修正してもよいか

推奨しない。プラグインがアップデートされるたびに修正が上書きされ、その都度同じ変更を加えなければならなくなる。子テーマや Code Snippets を使う方法なら、アップデートに影響されず継続的に動作する。

他の金額表示(税額や値引き額)も倍増している場合の対処は

同じヘルパークラス内で定義されている get_tax()get_discount() にも同様の静的変数の加算構造がある可能性が高い。それらのメソッドも同じ要領でカスタムクラス内にオーバーライドし、内部で該当の静的変数をリセットする処理を加えるとよい。

子テーマを使っていない場合でも対応できるか

子テーマがない場合は Code Snippets プラグインが便利だ。スニペットとしてクラス定義を追加すれば、テーマに依存せず同じ修正を適用できる。テンプレートの書き換えは手動で行う必要があるが、クラスの読み込み自体はスニペット経由で問題なく動作する。

修正後に PDF が真っ白になる場合の確認点は

クラス名やメソッド名のスペルミス、オートローダーがカスタムクラスを見つけられていないケースが考えられる。まず PHP のエラーログを確認し、クラスが見つからないという趣旨の致命的エラーが出ていないか調べる。出ている場合はクラス定義の記述ミスか、定義のタイミングが早すぎる可能性があるため、init フックなどで定義を遅らせると改善することがある。

この記事のポイント

  • get_total() の多重呼び出しで合計が倍増するのは、静的変数 self::$total が加算され続ける設計のため
  • プラグイン本体を直接修正せず、子テーマの functions.php でカスタムクラスを定義する
  • カスタムクラス内で get_total() をオーバーライドし、計算前に self::$total = 0; でリセットする
  • PDF テンプレート側の呼び出しをカスタムクラスに差し替え、キャッシュ削除後に動作確認する
  • 同様の構造を持つ get_tax()get_discount() も併せて修正を検討する
WooCommerce 11.0でget_queried_object()がショップページでもWP_Postを返す改善

WooCommerce 11.0でget_queried_object()がショップページでもWP_Postを返す改善

WooCommerce 11.0より、ショップページで get_queried_object() を呼び出した際の戻り値の型が WP_Post_Type から WP_Post に統一される。これまでショップページだけが例外的に商品の投稿タイプオブジェクトを返していたが、今回の変更でWordPress標準の挙動と一貫性が保たれることになる。

この修正は、WooCommerceが内部的に管理するクエリの取り扱いをWordPressコアに合わせるもので、テーマやプラグインの開発者が「ショップページかどうか」を意識せずに get_queried_object() を扱えるようにする狙いがある。フロントページにショップページを設定している場合も同様の挙動となる。

WooCommerce 11.0のショップページ改善

WooCommerce 11.0のショップページ改善

get_queried_object() は現在のWordPressクエリに対応するオブジェクトを取得する標準関数だ。通常の固定ページや投稿ページでは WP_Post オブジェクトを返すが、これまでのWooCommerceではショップページに限り WP_Post_Type オブジェクト、つまり商品(product)の投稿タイプ情報を返していた。この不一致が開発者にとって混乱の元となっていた。

WooCommerce Developer Blogの説明によれば、ショップページで get_queried_object() を呼び出して「商品アーカイブであること」を判定するコードを書いていた場合、この変更の影響を受ける可能性がある。逆に言えば、今回の修正で is_shop() のような条件分岐タグと get_queried_object() の戻り値の関係が整理され、より直感的なコードが書けるようになる。

WooCommerce 10.x までの挙動(Before)
Shopページ WP_Post_Type (商品の投稿タイプ情報)
その他固定ページ WP_Post (ページの投稿オブジェクト)
Shopページだけが例外で、他のページと異なるオブジェクト型を返していた
WooCommerce 11.0 以降の統一された挙動(After)
Shopページ WP_Post (ショップ固定ページの投稿オブジェクト)
その他固定ページ WP_Post (ページの投稿オブジェクト)
すべてのページで一貫して WP_Post を返すように統一された

この変更の背景には、WordPressの「投稿ページ」設定と同様にショップページでも WP_Post を返すべき、という設計上の判断がある。WooCommerce 11.0ではこの長年の不一致が解消され、より予測しやすいAPIへと改善された。

影響を受けるコードの判断方法

影響を受けるコードの判断方法

自作のテーマやプラグインでショップページのクエリオブジェクトを参照している場合、以下のいずれかの関数やプロパティを使用していないか確認する必要がある。

  • get_queried_object() を呼び出している
  • get_queried_object_id() を呼び出している
  • $query->queried_object に直接アクセスしている
  • $query->queried_object_id に直接アクセスしている

これらのコードがショップページ上で実行され、戻り値として WP_Post_Type オブジェクトを期待しているなら、WooCommerce 11.0へのアップデート後に動作が変わる可能性が高い。とくに、queried_object->labels->name などのプロパティに依存している場合は要注意だ。

Before / After コードの比較

具体的なコードの違いを見てみよう。以下はショップページでの get_queried_object() の戻り値の変化を示している。

// WooCommerce 10.x まで Shopページのみ例外
get_queried_object();          // → WP_Post_Type
get_post_type_object( 'product' ); // → WP_Post_Type

// その他の固定ページ
get_queried_object();          // → WP_Post
get_post_type_object( 'product' ); // → WP_Post_Type
// WooCommerce 11.0 以降 Shopページも含めて統一
get_queried_object();          // → WP_Post
get_post_type_object( 'product' ); // → WP_Post_Type

この変更の影響を受けないケース

次のような状況では、WooCommerce 11.0の変更による影響はなく、既存のコードはそのまま動作する。

  • 単一の商品ページ(single-product)では引き続き商品の WP_Post オブジェクトが返る
  • 商品カテゴリやタグ、ブランド、属性などのタクソノミーページでは WP_Term オブジェクトが返る
  • その他の投稿タイプアーカイブや個別ページはもともと変更の対象外
  • is_shop()is_archive()is_post_type_archive( 'product' ) といった条件分岐関数の挙動は従来どおり変わらない

開発者が取るべき具体的な対応

開発者が取るべき具体的な対応

もし既存のコードがショップページで get_queried_object() の戻り値を WP_Post_Type として扱っている場合、WooCommerce 11.0へのアップデートに備えて改修が必要だ。修正の基本方針は「オブジェクトの型をチェックしてからプロパティにアクセスする」ことにある。

商品の投稿タイプ情報を取得する推奨方法

商品の WP_Post_Type オブジェクトが必要な場合は、get_post_type_object() を使うのが安全で推奨される方法だ。この関数はWooCommerceのバージョンに関係なく常に正しいオブジェクトを返す。

$product_post_type = get_post_type_object( 'product' );

if ( $product_post_type instanceof WP_Post_Type ) {
    // 商品のWP_Post_Typeオブジェクトは
    // get_post_type_object() から引き続き取得できる
    $singular_name = $product_post_type->labels->singular_name;
}

ショップページのWP_Post情報を扱うコード例

ショップページ自体の情報(ページタイトルやスラッグなど)を取得したい場合は、WooCommerce 11.0以降は get_queried_object() から直接 WP_Post としてアクセスできるようになる。以下はその典型的な使用例だ。

$shop_page = get_queried_object();

if ( $shop_page instanceof WP_Post ) {
    // WooCommerce 11.0以降、ショップページでも
    // WP_Postとして扱える
    $shop_title = $shop_page->post_title;
    $shop_slug  = $shop_page->post_name;
}
修正の流れと対応手順
STEP 1 ショップページで get_queried_object() / $query->queried_object を使っている箇所を特定する
STEP 2 戻り値を WP_Post_Type として使っているか確認する( instanceof や型チェックをしていない場合)
STEP 3 get_post_type_object( 'product' ) で商品の投稿タイプ情報を個別に取得し、既存コードを書き換える
STEP 4 テスト環境でWooCommerce 11.0にアップデートし、ショップページが正しく表示されるか検証する

重要なのは、get_queried_object() の戻り値に依存した条件分岐を書く前に、必ず instanceof でオブジェクトの型をチェックする習慣をつけることだ。これにより、WooCommerceの将来のアップデートや他のプラグインとの競合にも強いコードになる。

この記事のポイント

  • WooCommerce 11.0ではショップページの get_queried_object()WP_Post を返すように統一される
  • 商品の投稿タイプ情報が欲しい場合は get_post_type_object( 'product' ) を使用する
  • is_shop() などの条件分岐関数の挙動は変わらないため、ページ判定ロジックの修正は不要
  • 影響を受けるコードは、おもにショップページでクエリオブジェクトのプロパティに直接アクセスしている箇所
  • アップデート前に instanceof による型チェックを追加し、テスト環境で検証するのが安全な移行手順
WordPress 7.0.1でクラシックエディタ保存できない時の原因と直し方

WordPress 7.0.1でクラシックエディタ保存できない時の原因と直し方

WordPress 7.0.1 更新後にクラシックエディタや WPBakery などのページビルダーで投稿や固定ページを保存できない、下書きが消えるといった症状は、PHP 8.4 との互換性問題が原因だ。PHP バージョンを 8.3 以下に切り替えればこの問題は解消する。

クラシックエディタで保存できずリダイレクトされる現象の正体

クラシックエディタで保存できずリダイレクトされる現象の正体

WordPress 7.0.1 に更新した直後から、クラシックエディタプラグインを有効化していると「公開」「下書き保存」をクリックしても保存されず、投稿一覧にリダイレクトされてしまう。保存したはずの記事や固定ページは一覧からも消え、下書きにも残らない。

さらにややこしいのは、ブロックエディタ(Gutenberg)では問題なく保存できるという点だ。クラシックエディタのプラグインを無効化せずとも、ブロックエディタ側で開いて操作すれば保存は成功する。このため一見すると「特定のプラグインだけが壊れている」ように見えるが、実際にはクラシックエディタ系や WPBakery など旧来の編集画面に依存するツール全般で同じ症状が出る。

この現象はプラグイン側の不具合ではなく、WordPress コアが動作する PHP のバージョンに起因する。特に PHP 8.4 環境で顕在化しやすい。

なぜ PHP 8.4 でクラシックエディタが動作しなくなるのか

なぜ PHP 8.4 でクラシックエディタが動作しなくなるのか

根本原因は PHP 8.4 で廃止または挙動が変更された関数や構文が、クラシックエディタの編集画面や保存処理の中で使われていることにある。古いエディタ画面は WordPress コアの一部として動作するが、その内部処理が新しい PHP の厳格な型チェックや廃止予定の警告(Deprecated)に引っかかり、画面遷移やデータ保存に失敗する。

たとえば、PHP 8.4 では暗黙の nullable 型宣言が非推奨になり、引数のデフォルト値や型宣言の扱いが厳密化された。WordPress の管理画面まわりには長い歴史を持つコードが多く、こうした細かな PHP の変更に対してすべてのプラグインやテーマが追随できているわけではない。

ブロックエディタが正常に動作するのは、ブロックエディタの保存処理が REST API を経由し、比較的新しいコードベースで実装されているため、PHP 8.4 の影響を受けにくいからだ。

PHP バージョンを 8.3 に切り替えて問題を解消する

PHP バージョンを 8.3 に切り替えて問題を解消する

現時点で最も確実な対処法は、サーバーの PHP バージョンを 8.3 にダウングレードすることだ。PHP 8.4 はリリースされたばかりで、WordPress エコシステム全体の完全な互換性が確保されるまでは安定動作が見込める 8.3 を使うほうが無難である。

PHP 8.4
クラシックエディタ保存不可 → 一覧にリダイレクト → 記事消失
STEP 1 サーバー管理画面から PHP 設定を開く
STEP 2 PHP 8.3 を選択して適用する
PHP 8.3
クラシックエディタ正常保存・下書きも残る

多くのレンタルサーバーではコントロールパネル(cPanel や独自管理画面)から簡単に PHP バージョンを切り替えられる。

サーバー管理画面での具体的な操作

cPanel を使っている場合は「PHP の選択」または「MultiPHP Manager」といったメニューを探す。対象ドメインを選択し、ドロップダウンメニューから「PHP 8.3」を選んで保存するだけだ。変更は数分以内に反映される。

独自の管理画面を提供しているサーバーでも、多くの場合「PHP 設定」「PHP バージョン管理」といった項目がある。もし見つからなければサーバー運営会社のサポートに「PHP バージョンを 8.3 に変更したい」と伝えれば対応してくれるケースが多い。

変更前に現在の PHP バージョンを確認する

WordPress 管理画面の「ツール」→「サイトヘルス」→「情報」タブを開き、「サーバー」セクションを見ると現在の PHP バージョンが表示されている。ここで 8.4 以上であれば今回の問題に該当する可能性が高い。

PHP 8.3 への切り替えでも直らない場合の追加確認

PHP 8.3 への切り替えでも直らない場合の追加確認

ごくまれに、PHP バージョンを下げても問題が続くことがある。そんなときは次の3点を順に確かめる。

ブラウザキャッシュと WordPress キャッシュのクリア

PHP の変更後にブラウザのキャッシュが残っていると、古い JavaScript や CSS で画面が正しく動作しないことがある。ブラウザのキャッシュを削除するか、シークレットウィンドウで管理画面を開き直す。また、WordPress 側でキャッシュプラグインを使っている場合はそのキャッシュもすべて削除する。

管理画面で JavaScript エラーが出ていないか調べる

ブラウザの開発者ツール(F12 キー)を開き、「コンソール」タブで赤いエラーが出ていないか確認する。保存ボタンを押した瞬間に何らかの JavaScript エラーが記録されていれば、それが原因の手がかりになる。

WordPress のデバッグモードでログを取得する

wp-config.php に以下のコードを追加してデバッグモードを有効にすると、保存時のエラーが wp-content/debug.log に記録される。

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

ログに「Deprecated」や「Fatal error」が記録されていれば、それが直接の原因を示している。ただし、大半のケースでは PHP 8.3 への切り替えだけで問題が解消するため、ログを調べるのはレアケースの最終手段と考えてよい。

よくある質問

PHP 8.3 に戻すとセキュリティ面で問題はないか

PHP 8.3 は現在もアクティブサポートが継続しており、セキュリティ修正は提供され続けている。WordPress 公式の推奨バージョンでもあるため、本番環境で使っても安全だ。無理に最新の 8.4 に上げるよりも、安定した 8.3 で運用するほうが結果的にリスクが低い。

PHP 8.3 に変更したのにクラシックエディタがまだ使えない

PHP の変更がサーバーに完全に反映されるまで数分かかることがある。まずは数分待ってから再度試す。それでも改善しない場合は、一度プラグインを無効化して再度有効化してみる。また、前述のキャッシュクリアも忘れずに行う。

WPBakery や他のページビルダーでも同じ症状が出るのか

出る。クラシックエディタだけでなく、WPBakery をはじめとする旧型の編集画面を使うページビルダー全般が PHP 8.4 の影響を受ける。これらもブロックエディタと異なり、内部の保存処理が古いコードに依存しているためだ。

PHP バージョンを自由に変更できないサーバーではどうすればいいか

サーバー管理画面に PHP バージョンの変更オプションがない場合は、サーバー運営会社のサポートに連絡して「PHP 8.3 への切り替えを依頼したい」と伝える。ほとんどの会社は対応してくれる。もし変更ができないと言われた場合は、PHP 8.4 の環境でも動作するように WordPress のアップデートを待つか、ブロックエディタに一時的に切り替えて運用するしかない。

この記事のポイント

  • WordPress 7.0.1 でクラシックエディタ保存不可になる原因は PHP 8.4 の互換性問題
  • PHP バージョンを 8.3 に下げると問題は即座に解消する
  • ブロックエディタは PHP 8.4 でも正常に動作するため一時的な回避策になる
  • 変更後はブラウザキャッシュと WordPress キャッシュを忘れずにクリアする
  • PHP 8.3 は公式推奨でありセキュリティ面でも安全に運用できる
データベース接続確立エラーの原因と復旧手順

データベース接続確立エラーの原因と復旧手順

「データベース接続確立エラー」でサイトがダウンした場合、まずはサーバー会社に連絡してデータベースサーバーの稼働状況を確認し、wp-config.php の接続情報を照合するのが最短の復旧手順だ。自分でできる対処は限られているため、慌てずに切り分けを進める。

なぜ「データベース接続確立エラー」が突然発生するのか

なぜ「データベース接続確立エラー」が突然発生するのか

このエラーは WordPress がデータベースに接続できないときに表示される。日本語環境では「データベース接続確立エラー」というメッセージが画面に表示され、サイト全体が表示できなくなる。原因は大きく4つに分けられる。

  • wp-config.php 内のデータベース名・ユーザー名・パスワード・ホスト名のいずれかが誤っている
  • データベースサーバー自体がダウンしている(サーバー障害・メンテナンス)
  • データベースサーバーは稼働しているが、負荷集中で応答不能になっている
  • データベースが破損している(テーブルクラッシュなど)

サイトを長期間触っていなかったのに突然エラーが出た場合は、サーバー側で MySQL や MariaDB のバージョンアップ、パスワード変更、セキュリティ設定の変更が行われた可能性が高い。WordPress 側の設定ファイルは変わらないまま、サーバー側の接続条件だけが変わることで不一致が起きる。

Before(エラー発生中)
ブラウザに「データベース接続確立エラー」が表示される
wp-config.php とデータベースの認証情報が不一致、または DB サーバーが停止
After(復旧後)
サイトが正常表示される
正しい接続情報で WordPress がデータベースにアクセスできる状態
エラー状態  復旧後

エラーが出たらまず試す3つの切り分け

エラーが出たらまず試す3つの切り分け
STEP 1 サーバー会社にデータベースサーバーの稼働状況を確認する
STEP 2 wp-config.php の接続情報をサーバー管理画面の値と照合する
STEP 3 phpMyAdmin などでデータベースに直接接続できるか試す

サーバー会社にデータベースサーバーの状態を問い合わせる

最も確実で早いのが、利用しているサーバー会社のサポートに連絡することだ。データベースサーバーがダウンしていれば、自分で何をしても復旧しない。管理画面にログインできなくても、サーバー会社のコントロールパネル(cPanel や独自管理画面)にアクセスできれば、そこからデータベースの状態を確認できる場合もある。

特に共有サーバー(複数ユーザーで1台のサーバーを共有するプラン)では、他のユーザーの影響でデータベースサーバーに負荷がかかり、一時的に応答しなくなることがある。この場合もサーバー会社側で対処が必要になる。

wp-config.php の接続情報を確認する

FTP ソフトやサーバーのファイルマネージャーで WordPress のインストールディレクトリにある wp-config.php を開き、以下の4つの定数を確認する。

define( 'DB_NAME', 'database_name_here' );
define( 'DB_USER', 'username_here' );
define( 'DB_PASSWORD', 'password_here' );
define( 'DB_HOST', 'localhost' );

これらの値がサーバーのデータベース管理画面(phpMyAdmin やサーバー会社のコントロールパネル)で設定した値と完全に一致しているか確認する。サーバー会社がパスワードをリセットした場合や、セキュリティアップデートでホスト名が localhost から mysqlcluster2.example.com のような専用ホスト名に変更されるケースがある。

wp-config.php に一時的な確認コードを入れる

接続情報が正しいかどうかを切り分けるには、wp-config.php に以下のテストコードを追加する方法も有効だ。エラーメッセージの詳細が表示され、単なる認証エラーなのか、サーバー自体に到達できないのかが判別できる。

$link = mysqli_connect( DB_HOST, DB_USER, DB_PASSWORD, DB_NAME );
if ( ! $link ) {
    die( '接続失敗: ' . mysqli_connect_error() );
}
echo '接続成功';
die();

このコードを wp-config.php/* That's all, stop editing! Happy blogging. */ より上に追記し、サイトにアクセスする。「接続失敗」と表示されれば認証情報かサーバー到達性の問題、「接続成功」と表示されれば WordPress 本体やプラグイン側の別の要因が疑われる。確認が終わったら必ずこのコードを削除する。

phpMyAdmin からデータベースに直接接続する

サーバー会社のコントロールパネルから phpMyAdmin にアクセスし、該当のデータベースを開けるか確認する。開ければ、データベースサーバーは稼働しており、認証情報も正しいことがわかる。開けない場合は、ユーザー名・パスワードが誤っているか、そのユーザーにデータベースへのアクセス権限が付与されていない。

phpMyAdmin 自体が開けない、または読み込みに極端に時間がかかる場合は、データベースサーバーの高負荷やダウンが原因だ。この場合もサーバー会社への連絡が必要になる。

データベースの修復が必要なケース

データベースの修復が必要なケース

wp-config.php の情報が正しく、データベースサーバーも稼働しているのに接続エラーが出る場合、データベースのテーブルが破損している可能性がある。この修復は WordPress の自動修復機能で対応できる。

wp-config.php に以下の1行を追加する。

define( 'WP_ALLOW_REPAIR', true );

その後、ブラウザで https://あなたのサイトのURL/wp-admin/maint/repair.php にアクセスすると、データベース修復画面が表示される。「データベースを修復」または「データベースを修復して最適化」ボタンをクリックすれば修復が実行される。修復完了後は、セキュリティのために必ず追加した行を削除する。

管理画面にログインできない場合の対処

管理画面にログインできない場合の対処

「データベース接続確立エラー」が出ている間は、WordPress の管理画面(/wp-admin)にもアクセスできない。この状態では wp-config.php の確認や修正を WordPress の管理画面から行うことはできず、必ずサーバー側のファイルマネージャーか FTP ソフトを使う必要がある。

FTP の接続情報がわからない場合も、サーバー会社のサポートに連絡すれば、コントロールパネルへのログイン方法やファイルマネージャーの使い方を案内してもらえる。WordPress のログイン情報よりも先に、サーバーの管理画面にアクセスできる状態を確保することが復旧の第一歩だ。

再発を防ぐための日常的な対策

再発を防ぐための日常的な対策

データベース接続エラーは突然発生し、サイト全体が完全に停止するため、予防と早期発見の仕組みを整えておくことが重要だ。

  • サーバー会社のデータベース稼働状況を定期的にチェックする(障害通知メールの設定)
  • データベースの定期バックアップを自動化する(サーバー側のバックアップ機能やプラグインを利用)
  • wp-config.php のバックアップを手元に保管し、接続情報をメモしておく
  • サーバー会社のコントロールパネルと FTP のログイン情報を常に最新に保つ

特にレンタルサーバーの共有プランを利用している場合、サーバー会社がメンテナンスやセキュリティアップデートでデータベースの接続設定を変更することがある。変更の予告メールを見逃さないよう、サーバー会社からのメールは確実に受信できるアドレスに設定しておく。

よくある質問

データベース接続エラーと「重大なエラー」は別のものか

別のエラーだ。「データベース接続確立エラー」はデータベースとの通信そのものができない状態で、サイト全体が表示されない。「このサイトで重大なエラーが発生しました」は WordPress 本体やプラグインの PHP エラーで、管理画面にメールが届く場合もある。後者はデータベースに接続できていることが前提になる。

wp-config.php を修正したのに直らない場合はどうすればよいか

データベースサーバー自体が停止しているか、MySQL のサービスが落ちている可能性が高い。サーバー会社のコントロールパネルで MySQL の状態を確認し、停止していれば再起動を試みる。操作権限がない場合はサーバー会社に依頼する。

データベースのユーザー名やパスワードを忘れた場合はどうするか

サーバーのコントロールパネル(cPanel の「MySQL データベース」など)から確認または再設定できる。WordPress の管理画面からは確認できないため、必ずサーバー側の管理画面を使う。パスワードをリセットした場合は、wp-config.php の DB_PASSWORD も新しい値に更新する必要がある。

データベースの修復でデータが消えることはあるか

WP_ALLOW_REPAIR による修復は、破損したテーブルの構造を修復する機能で、保存されている投稿や設定データを削除することはない。ただし、修復作業の前には必ずデータベースのバックアップを取得しておくことが望ましい。

エラーが断続的に発生する場合の原因は何か

データベースサーバーの負荷が一時的に高まっているか、同時接続数の上限に達している可能性がある。アクセス集中時だけエラーが出る場合は、サーバースペックやプランの見直しを検討する。また、プラグインが非効率なデータベースクエリを大量に発行していないかも確認する。

この記事のポイント

  • データベース接続エラーは wp-config.php の誤りかサーバー側の障害が主因
  • エラー発生時は管理画面にログインできないため、FTP やサーバー管理画面で対応する
  • サーバー会社に連絡してデータベースサーバーの稼働状態を確認するのが最短の復旧手段
  • テーブル破損が疑われる場合は WP_ALLOW_REPAIR で修復を試みる
  • 日常的にバックアップと接続情報の控えを取っておくことで復旧時間を短縮できる
WordPress会員データが大量削除された時の原因と復旧手順

WordPress会員データが大量削除された時の原因と復旧手順

WordPress サイトで会員データが突然数千件単位で削除され、WP Activity Log に「Unknown user」として記録される事態は、データベースへの直接アクセスか管理者権限の乗っ取りによる攻撃の可能性が高い。即座にサイトをメンテナンスモードに切り替え、被害拡大を防ぎつつバックアップから復旧し、侵入経路を特定して再発を防ぐ必要がある。

なぜ突然会員データが大量削除されたのか

この事象の最大の特徴は、削除を実行したユーザーが「Unknown user」と表示される点にある。通常、WordPress の操作ログにはユーザー名かユーザー ID が記録されるが、ここに名前が出ないということは、wp_users テーブルを経由しない削除が行われていることを示している。考えられる原因は大きく3つに絞られる。

データベースへの直接操作

最も深刻なケースとして、攻撃者が SQL インジェクションや phpMyAdmin への不正アクセス、あるいはサーバーに仕込んだマルウェア経由でデータベースに直接 DELETE 文を実行している状況だ。この場合、WordPress のアクションやフィルターフックを一切通過しないため、WP Activity Log を含むどの監査プラグインもユーザーを特定できず「Unknown」となる。

管理者アカウントの乗っ取り

管理者権限を持つアカウントが乗っ取られ、攻撃者がそのアカウントで MemberPress の会員一括操作機能やデータベースクリーニング系プラグインを実行したケースだ。ただし、この場合は通常ユーザー名がログに残る。残っていないということは、攻撃者が操作後にユーザーごと削除したか、別の手段を使った可能性が高い。

REST API や XML-RPC の悪用

WordPress の REST API や XML-RPC に認証の弱点があると、外部から会員データの削除リクエストを送信される場合がある。特に、API 経由で直接データベース操作を行うカスタムエンドポイントがテーマやプラグインに存在すると、認証をすり抜けて大量削除が実行される危険がある。

大量削除が発生する3つの経路
A. データベース直接操作 SQL インジェクションやサーバー侵入により、DELETE 文を直接実行。WordPress のログを一切通過しないため「Unknown」になる。
B. 管理者アカウント乗っ取り 乗っ取った管理者で管理画面から一括削除。通常はユーザー名が残るが、アカウントごと削除された可能性もある。
C. REST API や XML-RPC の悪用 認証の脆弱性を突き、API 経由で削除リクエストを送信。プラグイン独自のエンドポイントに注意が必要。
最も深刻な経路  緊急調査が必要な経路

同時に多数のプラグイン更新が表示され、WordPress 7.0.1 への更新も同日にリリースされたという状況は、実際に重大な脆弱性が公表され、各開発者が一斉にパッチを配布している可能性を示唆している。更新が突如10件以上積み上がるのは、テーマやプラグインに含まれる共通ライブラリに脆弱性が見つかった場合によく見られるパターンだ。

攻撃を受けた直後にとるべき緊急対応の手順

攻撃を受けた直後にとるべき緊急対応の手順

被害の発覚から時間が経つほど、データ消失や情報流出の範囲は広がる。以下の手順を発見後30分以内に実行することで、二次被害を最小限に抑えられる。

STEP 1 サイトをメンテナンスモードに切り替え、外部からの全アクセスを遮断する
STEP 2 全プラグインとテーマを強制無効化し、攻撃者が仕込んだマルウェアの実行を止める
STEP 3 WP Activity Log をエクスポートし、攻撃元 IP と操作内容の全記録を保全する
STEP 4 直近の正常なバックアップからデータベースを復元する

メンテナンスモードでアクセスを遮断する

まず、攻撃が継続している可能性を想定し、サイト全体をメンテナンスモードに切り替える。管理画面にアクセスできる状態であれば、.maintenance ファイルを手動で作成する方法が最も確実だ。WordPress のルートディレクトリに .maintenance ファイルを配置し、以下の内容を記述すると、全訪問者にメンテナンス画面が表示される。

<?php
$upgrading = time();
?>

FTP やサーバーのファイルマネージャーでアクセスできない場合は、サーバー管理パネルから Web サーバー(Apache や Nginx)自体を停止するか、.htaccess に IP 制限をかけて特定の IP 以外をすべて拒否する方法も有効だ。

プラグインとテーマを強制的に無効化する

管理画面からプラグインを一括停止できない、あるいは管理画面自体が攻撃者にロックされている場合、FTP で /wp-content/plugins/ ディレクトリごとリネームする(例: plugins_backup)。これにより、WordPress は全プラグインを無効化した状態で起動する。同様に、/wp-content/themes/ から現在のテーマを除く全テーマを別ディレクトリに退避し、標準テーマ(Twenty Twenty-Five 等)のみを残す。

ログを保全して侵入経路を特定する

WP Activity Log のデータは攻撃者に消去される前にエクスポートする。CSV または JSON でダウンロードし、ローカルに保存する。このとき、サーバーのアクセスログ(access.log)とエラーログ(error.log)も必ず取得する。ログから得るべき情報は「攻撃元 IP」「削除が実行された正確な日時」「リクエスト URL(特に POST リクエスト)」「User-Agent」の4点だ。

「Unknown user」による削除操作が大量に記録されている場合、リクエスト URL が wp-admin/admin-ajax.phpwp-json/ を含んでいないかを重点的に確認する。これらが含まれていれば、AJAX や REST API 経由の攻撃である可能性が高い。

バックアップからの復旧とデータ整合性の確認

バックアップからの復旧とデータ整合性の確認

攻撃発生前の正常な状態がわかっているバックアップがあれば、それをリストアする。このケースのように2日前のバックアップが存在する場合、消失した会員データはその時点のものに戻るが、2日間に新規登録した会員や更新されたデータは失われるため、復旧後に差分を手動で補完する必要がある。

復旧の Before / After
Before(攻撃を受けた状態)
MemberPress 会員テーブルが数千件消失し「Unknown user」の削除ログのみが残っている。プラグイン更新が20件積み上がり、WP 7.0.1 が未適用。
After(復旧完了後)
バックアップから会員データをリストア。全プラグインと WP 本体を最新に更新し、不正ファイルを除去した状態でサイトを再公開。
攻撃直後の状態  復旧後の安全な状態

データベースをリストアする手順

バックアップが SQL ダンプファイル(.sql または .sql.gz)の場合、phpMyAdmin またはサーバーのコマンドラインからインポートする。WordPress のデータベース全体を置き換える場合は、まず現在の全テーブルを削除(DROP)してからインポートする。この操作は取り返しがつかないため、必ず現在のデータベースも別名でエクスポートしてから実行する。

# コマンドラインでのリストア例
mysql -u ユーザー名 -p データベース名 < backup.sql

リストア後、MemberPress の会員数が期待通りに戻っているか、会員のサブスクリプション状況や支払い履歴が正しく関連付けられているかを必ず確認する。特に、WooCommerce と連携している場合は wp_usermeta テーブルの整合性もチェックする必要がある。

再発を防ぐための恒久対策

再発を防ぐための恒久対策

復旧が完了したら、同じ攻撃を二度と受けないようにするための対策を即座に実施する。サーバー侵入を許した原因が残ったままだと、再度同じ経路から攻撃される危険が極めて高い。

全ファイルの改ざんチェックとマルウェアスキャン

WordPress のコアファイル、プラグイン、テーマのすべてについて、オリジナルの配布ファイルと比較して改ざんされていないかを確認する。WordPress の管理画面から「サイトヘルス」→「情報」→「ファイルの整合性」でコアファイルのチェックが可能だが、プラグインとテーマは手動かセキュリティプラグイン(Wordfence や Sucuri 等)を使ってスキャンする。特に、wp-content/uploads/ 内に .php ファイルが存在していないかを重点的に調べる。

管理者アカウントの総点検とパスワード再設定

すべての管理者アカウントについて、覚えのないユーザーが追加されていないか、権限が勝手に昇格されていないかを確認する。wp_users テーブルと wp_usermeta を直接確認し、不審な管理者を削除する。その上で、全管理者と編集者のパスワードを強制的にリセットし、可能であれば二要素認証(2FA)を導入する。WordPress 6.8 以降は標準でパスキー認証が利用できるため、セキュリティキーを使ったログインも有効な選択肢だ。

データベースのアクセス制限と監査の強化

データベースへの外部からの直接アクセスを遮断するため、phpMyAdmin などの管理ツールを公開ディレクトリに置かない、または IP 制限と HTTP 認証をかける。また、wp-config.php に以下の定数を追加して、WordPress のファイル編集機能を無効化しておくことで、管理画面を乗っ取られた場合でもテーマやプラグインのコードが書き換えられることを防げる。

define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', true); // 必要な場合のみ

XML-RPC と REST API のアクセス制限

XML-RPC を使用していない場合は .htaccess でブロックするか、プラグインで完全に無効化する。REST API は多くのプラグインが依存しているため完全には無効化できないが、認証が必要なエンドポイントに対して適切な権限チェックが実装されているかを確認する。特に、MemberPress やカスタムプラグインが提供する REST API エンドポイントは、開発元のドキュメントでセキュリティ設定を再確認する。

よくある質問

WP Activity Log に「Unknown user」と表示されるのは必ずハッキングか

必ずしもそうとは限らないが、高い確率で不正アクセスが疑われる。プラグインのバグやデータベースの不整合でも発生しうるが、同時に大量のデータが削除されている場合は攻撃の可能性を第一に考えるべきだ。特に、管理者権限を持たない IP からの操作が記録されている場合はほぼ確実に侵入されている。

プラグインの更新が突然大量に表示されたのはなぜか

共通ライブラリやフレームワークに重大な脆弱性が見つかり、複数のプラグインが一斉にセキュリティアップデートをリリースした可能性が高い。WordPress 本体の緊急アップデートが同日にリリースされていることも、何らかの広範囲に影響する脆弱性が公表されたことを示唆している。これらの更新は速やかに適用すべきだ。

バックアップから復旧した後、消えたデータは完全に戻るのか

バックアップ取得時点のデータは戻るが、それ以降に追加・変更されたデータは復元されない。MemberPress の会員情報の場合、新規登録者やサブスクリプションの変更履歴が失われるため、復旧後に会員からの問い合わせをもとに手動で補完する必要がある。決済情報は決済代行サービス側に残っていることが多いため、そちらを参照して復元できる場合もある。

WP 7.0.1 への更新はすぐに適用すべきか

重大なセキュリティ修正を含むマイナーアップデートの場合、速やかな適用が推奨される。ただし、大量削除が発生した環境では、まずバックアップからの復旧と侵入経路の遮断を完了させてから更新を行う。更新前に全ファイルの改ざんチェックを済ませ、マルウェアが残っていない状態で適用するのが安全だ。

この記事のポイント

  • 「Unknown user」による大量削除はデータベース直接操作か管理者乗っ取りが原因の可能性が高い
  • 発見後は即座にメンテナンスモードでサイトを遮断し、プラグインを強制無効化して攻撃を止める
  • WP Activity Log とサーバーログを直ちにエクスポートし、攻撃元 IP と侵入経路を特定する
  • バックアップからデータベースをリストアし、復旧後に全ファイルの改ざんチェックとマルウェアスキャンを実施する
  • XML-RPC の無効化、REST API の権限確認、二要素認証の導入で再発を防ぐ
myCred Toolkit Pro アップデート後の致命的エラーと復旧手順

myCred Toolkit Pro アップデート後の致命的エラーと復旧手順

WordPress サイトで myCred Toolkit Pro をアップデートした直後に「Class MWP_Module not found」という致命的エラーが発生し管理画面にもアクセスできなくなった場合は、最新バージョンで修正済みの可能性が高い。修正がまだ提供されていない場合でも、クラスファイルの読み込み順序を確認し手動で修正すれば復旧できる。

MWP_Module クラスが見つからない致命的エラーはなぜ起こるのか

MWP_Module クラスが見つからない致命的エラーはなぜ起こるのか

このエラーは、myCred Toolkit Pro 内の WooCommerce Plus 改修版アドオンが読み込まれる際、ベースクラス(親クラス)である MWP_Module がまだ定義されていない状態で、子クラスが呼び出されるために発生する。具体的には class-mwp-module-coupons.phpMWP_Module を継承しようとするが、その元となる抽象クラスファイルが先に読み込まれていないのだ。

本来なら abstract/class-mwp-abstract-module.php が先にロードされるべきところ、プラグインのアップデート時にファイルの欠落が起きたり、オートローダーの設定不備で読み込み順序が狂ったりすると、このエラーが表面化する。PHP は未定義クラスへの継承を許さないため、サイト全体が致命的エラーで停止してしまう。

アップデート直後にサイトがダウンした場合の緊急復旧手順

アップデート直後にサイトがダウンした場合の緊急復旧手順

エラーによって WordPress 管理画面にも入れなくなった状態では、FTP クライアントやサーバーのファイルマネージャを使ってプラグインを強制的に無効化する必要がある。データベースを直接操作する方法もあるが、ファイル名の変更がもっとも手軽で確実だ。

STEP 1 FTP クライアントでサーバーに接続し、/wp-content/plugins/ ディレクトリへ移動する
STEP 2 mycred-toolkit-pro フォルダを右クリックし、「名前の変更」で末尾に _disabled を付ける
STEP 3 ブラウザでサイトにアクセスし、管理画面 /wp-admin/ へログインできるか確認する
STEP 4 管理画面に入れたら、プラグイン一覧で Toolkit Pro が「無効」になっていることを確認し、旧バージョンへ差し替える準備をする

上の手順でプラグインを無効化すれば、サイトは正常に表示されるようになる。続いて、動作していた旧バージョン(例として 1.0.4)を再インストールして有効化するか、修正版が配布されているかを確認する。

手動でクラスファイルの読み込み順序を確認し修正する方法

手動でクラスファイルの読み込み順序を確認し修正する方法

開発元の修正版がまだ提供されていない、あるいは修正を待てない場合は、プラグインのファイルを手動で編集してクラスの読み込み順序を修正できる。修正の要点は、class-mwp-module-coupons.php に到達する前にベースクラスを確実に読み込ませることだ。

問題のファイルと修正箇所を特定する

エラーログに出力されたパスをもとに、wp-content/plugins/mycred-toolkit-pro/includes/addons/mycred-woocommerce-plus/mycred-woocommerce-plus-revamped/modules/class-mwp-module-coupons.php を開く。7 行目付近で MWP_Module を継承しているクラス定義があるはずだ。

ベースクラスのファイルは wp-content/plugins/mycred-toolkit-pro/includes/addons/mycred-woocommerce-plus/mycred-woocommerce-plus-revamped/abstract/class-mwp-abstract-module.php に存在する。これが読み込まれていないことが原因なので、子クラスのファイルの先頭で明示的に require_once を追加する。

修正前(エラー発生)
1 <?php
2
3 // エラー: 親クラスが不明
4 class MWP_Module_Coupons extends MWP_Module {
5
修正後(正常動作)
1 <?php
2 require_once plugin_dir_path( __FILE__ ) .
3 ../abstract/class-mwp-abstract-module.php‘;
4
5 class MWP_Module_Coupons extends MWP_Module {
6
修正前(親クラス未定義のまま実行)  修正後(require_once で事前に読み込み)

上記のように require_once を追加することで、クラス定義より前にベースクラスを確実に読み込める。ただし、この修正は自作テーマの functions.php に書くような一時しのぎとは異なり、プラグインのコアファイルを直接編集するため、アップデートで上書きされる可能性がある点を理解しておく必要がある。

オートローダーの確認と修正

モダンなプラグインは PHP のオートローダー(Composer の autoload など)を使ってクラスを動的に読み込む仕組みを採用している。myCred Toolkit Pro も Composer ベースのオートロードを利用している可能性が高く、composer.json の autoload 設定や名前空間のマッピングが正しいかを確認すると根本的な解決につながる。

プラグインディレクトリで composer dump-autoload -o を実行し、クラスマップを再生成するのも有効な手だ。ただし、サーバーに Composer がインストールされている必要があるため、ローカル環境で再生成してからファイルをアップロードする方法が現実的だ。

修正版がリリースされている場合の安全なアップデート手順

修正版がリリースされている場合の安全なアップデート手順

開発元から修正版が提供された場合、本番環境にいきなり適用するのは避け、最初にステージング環境で動作確認を行うのが鉄則だ。致命的エラーはサイト全体を巻き込むため、万が一のときに備えて必ずバックアップを取る。

STEP 1 本番サイトのデータベースと全ファイルをバックアップする(プラグイン「UpdraftPlus」やサーバー側のスナップショット機能を使う)
STEP 2 ステージング環境にバックアップを復元し、Toolkit Pro を最新版へアップデートする
STEP 3 WooCommerce のポイント付与やクーポン連携が正常に動くか、テスト注文を行って検証する
STEP 4 問題なければメンテナンス時間帯を設け、本番環境でも同様にアップデートする

ステージング環境がない場合は、本番環境の深夜帯などアクセスが少ない時間にメンテナンスモードへ切り替えてから実施する。アップデート後すぐに管理画面へアクセスできるか、フロントエンドにエラーが出ていないかを確認し、問題があればすぐに旧バージョンへロールバックできるよう、ファイルのバックアップを手元に残しておく。

よくある質問

myCred 本体をアップデートしていないと同様のエラーは起きるか

プラグインによっては、本体(myCred コア)とアドオン(Toolkit Pro)のバージョンに互換性が要求される。MWP_Module クラスは Toolkit Pro 内部の抽象クラスなので myCred コアのバージョンに直接は依存しないが、コアが古すぎると別の非互換エラーを引き起こす可能性がある。常に両方を最新に保つことが望ましい。

修正版が出るまでサイトを止めておくべきか

致命的エラーでサイトが完全に停止しているなら、前述の緊急復旧手順でプラグインを無効化するか旧バージョンへ巻き戻し、通常運用を再開してよい。ポイント機能が止まる影響を考慮し、必要なら代替手段を顧客に案内する。

エラーログはどこで確認できるか

WordPress のデバッグモードを有効にしていれば /wp-content/debug.log にエラー詳細が出力される。有効でない場合は wp-config.phpdefine( 'WP_DEBUG', true );define( 'WP_DEBUG_LOG', true ); を記述する。レンタルサーバーによってはエラーログが管理画面から閲覧できる場合もある。

子テーマの functions.php で読み込み順序を修正できるか

テーマの functions.php はプラグインより後に読み込まれるため、この方法では MWP_Module クラスを事前に定義することはできない。プラグインファイルの直接編集が必須になる。

この記事のポイント

  • myCred Toolkit Pro アップデート後の MWP_Module クラス欠落エラーは、読み込み順序の不備が主因
  • 緊急復旧は FTP でプラグインフォルダをリネームし、旧バージョンへ差し替える
  • 手動修正では子クラスのファイル冒頭に require_once を追加する
  • 開発元修正版を適用する際は必ずバックアップとステージング検証を行う
  • PHP のオートローダー設定や Composer のクラスマップ再生成も有効なアプローチ