タグアーカイブ WordPress

WC Vendors 2.7.0アップグレードでfatal errorが出た時の対処法

WC Vendors 2.7.0アップグレードでfatal errorが出た時の対処法

WC Vendors 2.7.0 にアップグレードした直後、サイト全体が「このサイトで重大なエラーが発生しました」の表示になり管理画面にもアクセスできなくなった場合、wcvendors_capability_product_types オプションの値が配列ではなく文字列で保存されていることが原因だ。WP-CLI を使えるかどうかで復旧手順を分けて対処する。

WC Vendors 2.7.0で管理画面にすら入れなくなる原因は何か

WC Vendors 2.7.0で管理画面にすら入れなくなる原因は何か

この問題は、プラグイン内部の関数 wcv_is_all_product_types_hidden()array_diff() を呼び出す際、引数として文字列を渡してしまうことで発生する。PHP 8 環境では型宣言が厳密になったため、ここで TypeError(致命的エラー)が起こり、サイト全体が HTTP 500 エラーで停止する。

関数に渡されるのは wcvendors_capability_product_types というオプションの値だ。このオプションは本来、商品タイプの配列(['simple', 'variable'] など)を保持すべきだが、古いバージョンの WC Vendors(特に 1.x 系)から移行してきたサイトでは、内部的に「simple」のような文字列のまま残っているケースがある。2.7.0 で追加された新しい関数には配列へのキャスト処理が含まれておらず、長期間眠っていた不正なデータが一気に致命的エラーとして表面化した。

2.5.1.1 以前
(array) によるキャストがあり、文字列でも配列として扱われていた
→ エラーは表面化せず、サイトは通常通り稼働
2.7.0 アップグレード後
array_diff() に文字列が直接渡され、PHP 8 で TypeError
→ サイト全体が HTTP 500 エラー、管理画面も開けない
エラー発生 正常動作

エラーのトリガーは wp_loaded フックで、これは WordPress の読み込みのかなり早い段階で実行される。そのため管理画面もフロントエンドも一切表示されず、ダッシュボードからプラグインを無効化するという通常の復旧手段が使えなくなってしまう。

管理画面にログインできない場合の応急処置(WP-CLI を使う)

管理画面にログインできない場合の応急処置(WP-CLI を使う)

サーバーに SSH でアクセスできる環境であれば、WP-CLI を使って不正なオプション値を直接修正するのが最も確実な回復方法だ。管理画面に入れなくても、この操作でサイトは即座に復旧する。

STEP 1 SSH でサーバーに接続する
STEP 2 WordPress のインストールディレクトリに移動する
STEP 3 以下のコマンドを実行し、オプションを配列形式で上書きする
STEP 4 サイトの表示を確認する
wp option update wcvendors_capability_product_types '["simple"]' --format=json

上記コマンドは wcvendors_capability_product_types オプションの値を強制的に JSON 配列として上書きする。["simple"] の部分は、自サイトで実際に有効にしていた商品タイプのスラッグに置き換える。可変商品や外部商品を使っていた場合は、["simple","variable","external"] のようにカンマ区切りで列挙する。値は連想配列ではなく、単純なリスト形式でなければならない。

WP-CLI を使えない場合のエラー復旧手順(FTP/ファイルマネージャー)

WP-CLI を使えない場合のエラー復旧手順(FTP/ファイルマネージャー)

レンタルサーバーでは SSH が利用できず、WP-CLI も使えないケースが多い。その場合は FTP またはサーバー付属のファイルマネージャーを使ってプラグインを一時的に無効化し、管理画面にアクセスできる状態に戻す。

  1. FTP クライアントまたはファイルマネージャーで /wp-content/plugins/ ディレクトリにアクセスする
  2. wc-vendors ディレクトリを探し、名前を wc-vendors-disabled に変更する
  3. ブラウザで管理画面の URL(yourdomain.com/wp-admin/)を開く
  4. 管理画面にログインできたら、wc-vendors-disabled をもとの wc-vendors に戻す(ただし有効化はしない)
  5. 管理画面の「プラグイン」で WC Vendors が「無効」になっていることを確認し、データベースの該当オプションを修正する手順に進む

ディレクトリ名の変更によってプラグインが強制的に無効化される仕組みを利用している。ファイル自体は削除せず、リネームするだけなので元に戻せる。管理画面に戻ったら、次のセクションで説明する根本的なオプション修正を行う。現時点で WC Vendors を再度有効化すると、同じエラーが再発するので有効化してはいけない。

根本的な修正をプラグインのアップデート前に済ませておく

根本的な修正をプラグインのアップデート前に済ませておく

WC Vendors の開発チームはこの問題を認識しており、将来のリリースで修正が反映される見込みだ。しかしアップデートを待つだけでは、同じサイトで別の箇所が再び同様のエラーを起こす可能性を抱えたままになる。管理画面にログインできる状態にしたら、データベース上のオプション値を正規化してしまおう。

最も簡便な方法は、先ほど WP-CLI で実行したコマンドと同じ操作を、データベース管理ツール(phpMyAdmin など)やカスタムスクリプトで行うことだ。具体的には wp_options テーブルを開き、option_namewcvendors_capability_product_types の行を探す。option_value カラムが文字列(例 simple)になっている場合、a:1:{i:0;s:6:"simple";} のようにシリアライズされた配列表現に書き換える。

PHP のシリアライズ形式を手書きするのはミスが怖い場合は、次のような安心な手順をとる。

  1. WC Vendors が無効化されていることを確認する
  2. 管理画面の「設定」→「WC Vendors」→「販売」→「商品タイプ」に進み、チェックボックスで適切な商品タイプを選んで保存する(これで正常な配列としてオプションが上書きされる)
  3. WC Vendors を有効化する

この方法は管理画面を使うため、データベースを直接触る必要がなく安全だ。ただしバージョン 2.7.0 では有効化した瞬間に wp_loaded フックのエラーが再発する可能性があるため、あらかじめプラグインファイルの該当行を一時的に修正するか、前述のキャストを適用しておくと確実だ。

よくある質問

エラーログを確認するにはどうすればよいか

サーバーのエラーログには wp-content/debug.log(WordPress のデバッグログ)や、Apache/Nginx のエラーログがある。WP-CLI が使えれば wp config set WP_DEBUG true --rawwp config set WP_DEBUG_LOG true --raw でログ出力を有効にした上で、エラーを再現させて wp-content/debug.log を確認する。共有サーバーではホスティングの管理画面からエラーログが見られることも多い。

WC Vendors をアップグレードする前に何か注意すべきことはあるか

メジャーバージョンアップを行う場合は、本番サイトに適用する前に必ずステージング環境でテストする。どうしても本番で行うなら、事前にデータベースのバックアップを取り、wcvendors_capability_product_types オプションの現在の値を確認しておく。WP-CLI で wp option get wcvendors_capability_product_types --format=json を実行し、値が配列形式になっていることを確かめればリスクを大幅に減らせる。

PHP のバージョンが 7.x 系ならこの問題は起きないか

PHP 7.x では array_diff() に文字列を渡しても Warning は出るが Fatal Error にはならないため、サイトが完全停止することはない。ただしエラー自体の根本原因は同じであり、動作は予期しない結果になる可能性が高い。推奨される PHP のバージョンは 8.x 系へ移行することであり、その前に対処しておくことが望ましい。

WC Vendors Free と Pro のどちらでも発生するのか

この問題は WC Vendors の無料版(Free)のコア機能部分で発生している。Pro 版を併用している場合でも、同じオプション値を読み込むため影響を受ける可能性が高い。特に 1.x 系からバージョンを重ねてきたサイトは要注意だ。

この記事のポイント

  • WC Vendors 2.7.0 へのアップグレードでサイトが停止するのは array_diff() の型不一致が原因
  • 古いサイトでは wcvendors_capability_product_types が文字列で残っているケースがある
  • WP-CLI を使えるなら wp option update で即座に復旧できる
  • WP-CLI が使えない場合はプラグインディレクトリをリネームして管理画面に復帰する
  • 根本的には設定画面で商品タイプを保存し直すか、データベースの値を配列に正規化する
WooCommerce Social Loginに深刻度9.8の脆弱性。管理者アカウント乗っ取りの危険

WooCommerce Social Loginに深刻度9.8の脆弱性。管理者アカウント乗っ取りの危険

WooCommerce Social Loginプラグインに、未認証の攻撃者が任意のユーザーアカウントにログインできる重大な脆弱性が報告された。CVSSスコアは9.8と最高クラスの深刻度であり、管理者権限の奪取も可能になる。バージョン2.8.7以下を利用しているすべてのサイトが対象だ。

この脆弱性はAppleログイン処理に存在し、攻撃者は特別な権限を必要としない。正規のユーザーのメールアドレスさえ知っていれば、管理者を含む任意のアカウントに不正ログインできる。2026年8月1日に公開されたCVE-2026-8457として識別されており、即時対応が求められる。

深刻度9.8の認証バイパス脆弱性と影響範囲

深刻度9.8の認証バイパス脆弱性と影響範囲

Wordfenceのセキュリティ研究者によって発見されたこの脆弱性は、WooCommerce Social LoginのAppleサインイン機能に潜んでいた。ユーザーがAppleアカウントでログインする際、プラグインはAppleから返されるIDトークンの正当性を検証していなかった。このため攻撃者は、なりすましたいユーザーのメールアドレスを含む偽のトークンを作成し、認証をすり抜けられる。

被害を受けるのはWooCommerce Social Loginのバージョン2.8.7以下の全インストールだ。プラグインを有効化しているサイトであれば、特別な設定ミスがなくても攻撃が成立する。攻撃者はユーザー名やパスワードを一切知る必要がなく、標的のメールアドレスさえ分かれば管理者権限でログイン可能になる。

従来の認証バイパス手法との比較(Before)
従来型の脆弱性 権限昇格やCSRFなどを悪用し、既存セッションを乗っ取る
※攻撃成立には何らかのユーザー操作やログインセッションが必要なケースが多い
今回の脆弱性(After)
認証バイパス(未認証) 偽トークンひとつで管理者アカウントへ直接ログイン
※外部からの1リクエストで完了するため、被害の確認や遮断が極めて難しい

一般的なWordPressの脆弱性では、攻撃者が何らかの権限をあらかじめ持っていたり、管理者がリンクをクリックするなどの操作が必要になることが多い。しかし今回は、攻撃者が標的サイトにリクエストを送るだけで管理者アカウントにログインできてしまう。いわゆる「認証なしの管理者乗っ取り」に分類され、CVSS 9.8という評価はその直接的な危険性を反映している。

なぜこれほど危険なのか

なぜこれほど危険なのか

認証バイパスにより管理者権限を取得した攻撃者は、WooCommerceサイトの全データを自由に操作できる。具体的には、顧客情報や注文データの窃取、不正な管理者アカウントの追加、プラグインやテーマの改ざんによるマルウェア注入、支払い情報への介入などが考えられる。さらに、サイトのSEO評価を意図的に下げるスパムリンクの埋め込みや、Googleからのインデックス削除といった攻撃も容易に行われてしまう。

WooCommerceを利用するECサイトでは、顧客の個人情報や購入履歴が保存されている。こうしたデータが流出した場合、個人情報保護法やGDPRなどの規制違反に発展する可能性もある。サイトの信用失墜だけでなく、法的なリスクや多額の損害賠償にまでつながりかねない。

攻撃者が取得できる権限と波及範囲
管理者権限 サイト設定・プラグイン・テーマの完全制御
顧客データ 氏名・住所・購入履歴・メールアドレスの窃取
SEO被害 サイト改ざん・スパムリンク注入・検索順位の急落

WooCommerceのコア機能や他の決済プラグインでは、こうした認証処理に対する検証が厳格に行われている。しかし、Social LoginプラグインのAppleログイン部分だけが例外的に署名検証を欠いていた。そのため、攻撃の標的として非常に狙われやすい。

Appleログイン処理の具体的な問題点

Appleログイン処理の具体的な問題点

Appleサインインでは、ユーザーが認証を完了すると、AppleのサーバーからIDトークンと呼ばれるデータがサイト側に送られる。このトークンにはユーザーのメールアドレスなどの情報が含まれ、改ざんを防ぐためにAppleの秘密鍵で電子署名が付与されている。プラグインは本来、Appleが公開している鍵を使ってこの署名を検証し、トークンが本物であることを確認しなければならない。

ところが、WooCommerce Social Loginはこの署名検証のステップを実装しておらず、受け取ったメールアドレスをそのまま信頼してログイン処理に使っていた。結果として、攻撃者が偽のIDトークンを作り、その中に標的ユーザーのメールアドレスを入れて送信するだけで、そのユーザーとして認証が通ってしまう状態になっていた。

Wordfenceの調査によると、管理者ロールかどうかのチェックも行われていなかった。攻撃者が管理者のメールアドレスを指定すれば、管理画面へのフルアクセスが即座に与えられる。これはIDトークンに含まれる「email」フィールドを、ログインにそのまま使う実装ミスに起因している。

脆弱性のある処理(Before)
Apple IDトークン 署名検証をスキップ
メールアドレス抽出 admin@example.com
ログイン成功 管理者セッション発行
※攻撃者は偽トークンを送るだけで任意のユーザーになりすませる
本来あるべき処理(After)
Apple IDトークン Apple公開鍵で署名検証
検証成功時 メールアドレスでユーザーを特定
検証失敗時 ログイン拒否
※改ざんされたトークンはここでブロックされる

つまり、IDトークンの署名確認という重要な防御ラインがまるごと欠落していたわけだ。この種の不備は、OpenID ConnectやOAuth 2.0を利用するソーシャルログイン実装では絶対にあってはならないものであり、Wordfenceの報告では「未認証の攻撃者が、偽造したid_tokenのペイロードに対象ユーザーの電子メールアドレスを含めて送信するだけで、管理者を含む任意のアカウントでログインできる」と指摘されている。

影響を受けるバージョンと今すぐ取るべき対策

影響を受けるバージョンと今すぐ取るべき対策

この脆弱性の影響を受けるのは、WooCommerce Social Loginバージョン2.8.7以下のすべてのリリースだ。8月1日の公開後、プラグイン開発元はすぐに修正版2.8.8をリリースしている。Wordfenceは、該当バージョンを使用しているユーザーに対して、2.8.8またはそれ以降のバージョンへの即時アップデートを強く推奨している。

アップデートを適用しないまま放置すると、攻撃者に管理者権限を奪取された後に、バックドアを仕込まれたり、サイトの完全な乗っ取りが発生する可能性が高い。特にWooCommerceサイトでは決済情報や顧客データが絡むため、被害が拡大する前に一刻も早く更新を済ませてほしい。

  • WordPress管理画面から「プラグイン」→「インストール済みプラグイン」を開く
  • 「WooCommerce Social Login」を探し、利用可能なアップデートがあれば「今すぐ更新」をクリック
  • バージョンが2.8.8以上になっていることを確認する
  • 万が一、プラグインをすぐに更新できない事情がある場合は、一時的にプラグインを無効化する

また、サイトの管理者アカウントに不正なログインがなかったかどうか、アクセスログやユーザー一覧を至急確認してほしい。身に覚えのない管理者アカウントが追加されている場合は、すでに攻撃を受けている可能性がある。その場合は、プラグインの更新だけでなく、全ユーザーのパスワードリセットや、サイト全体のマルウェアスキャンも併せて実施する必要がある。

この記事のポイント

  • WooCommerce Social Login 2.8.7以下にCVSS 9.8の認証バイパス脆弱性が存在する
  • AppleログインのIDトークン署名検証が行われておらず、攻撃者が任意のユーザーになりすませる
  • 管理者アカウントも標的になるため、ECサイトの全データが危険にさらされる
  • 修正版2.8.8への即時アップデートが必須
  • すでに攻撃を受けた可能性がある場合は、ユーザー一覧の確認とサイト全体のセキュリティチェックを推奨
WordPress 7.0 ブロックエディターで多言語プラグイン Bogo 有効時に REST API 500 エラーが出る原因と対処

WordPress 7.0 ブロックエディターで多言語プラグイン Bogo 有効時に REST API 500 エラーが出る原因と対処

WordPress の多言語プラグイン Bogo を有効化した状態でブロックエディターを開くと、カテゴリーなどのタクソノミーパネルが空になり、REST API が 500 Internal Server Error を返す症状は、Bogo が REST API に付与する lang パラメータと WordPress 7.0 のブロックエディター側のリクエスト処理が競合していることが主な原因だ。

なぜ Bogo とブロックエディターの組み合わせで REST API が 500 エラーを返すのか

なぜ Bogo とブロックエディターの組み合わせで REST API が 500 エラーを返すのか

この問題の核心は、ブロックエディターが内部で使用する REST API エンドポイントに対するリクエストにある。ブロックエディターは編集画面を表示する際、/wp-json/wp/v2/taxonomies/wp-json/wp/v2/users/〜 といった複数のエンドポイントに同時にリクエストを送信し、カテゴリー一覧や投稿者情報を取得している。

Bogo は多言語対応のために、これらの REST API リクエストに対して自動的に lang クエリパラメータを付与する。たとえば ?lang=en?lang=ja といった具合だ。このパラメータ追加の処理が、ブロックエディターの特定の内部リクエストと組み合わさった際に、サーバー側で PHP の致命的エラーを引き起こしている。

データベースから要求された言語のデータを取得しようとするが、ブロックエディターのコンテキストでは想定外の引数が渡され、結果として WP_Query やタクソノミー取得関数が WP_Error オブジェクトを返す。これが REST API のレスポンス生成時に適切にハンドリングされず、500 エラーとして表面化する。

エラーの切り分けと原因特定の手順

エラーの切り分けと原因特定の手順

まずは問題が本当に Bogo とブロックエディターの組み合わせに限定されているのかを確認する。以下のフローに沿ってテストを進めると、原因の特定がスムーズになる。

STEP 1 Bogo 以外の全プラグインを無効化する
STEP 2 標準テーマ(Twenty Twenty-Five など)に切り替える
STEP 3 ブロックエディターで新規投稿画面を開き、カテゴリーパネルを確認する
STEP 4 ブラウザの開発者ツール「ネットワーク」タブで 500 エラーを探す

上記の最小構成でもエラーが再現する場合、Bogo とブロックエディターの直接的な競合と判断できる。なお、クラシックエディタープラグインをインストールして同じ操作を行った際に問題が発生しないことも、ブロックエディター固有の問題であることの強い証拠になる。

実用的な回避策と当面の対応

実用的な回避策と当面の対応

根本的な修正は Bogo プラグイン側のアップデートを待つ必要があるが、運用を止めずにしのぐ方法はいくつか存在する。状況に応じて以下を使い分ける。

クラシックエディターへの一時的な切り替え

最も確実で即効性のある回避策は、クラシックエディタープラグインをインストールして旧来の編集画面を使うことだ。クラシックエディターは REST API に依存したデータ取得を行わないため、Bogo の lang パラメータ付与が問題を引き起こす余地がない。

Before(ブロックエディター)
REST API 500 エラーでカテゴリーパネルが空
→ ブロックエディターの内部リクエストが lang パラメータと競合
After(クラシックエディター)
カテゴリーが正常に表示される
→ REST API 非依存のため競合が発生しない
エラー状態  回避後の状態

クラシックエディターは WordPress の公式プラグインディレクトリから無料でインストールできる。インストール後は「設定」→「投稿設定」からデフォルトのエディターを切り替えられる。

REST API への lang パラメータ付与をフィルターフックで制限する

Bogo は REST API リクエストに言語パラメータを付与する際、rest_dispatch_requestrest_pre_dispatch といったフィルターフックを経由している。子テーマの functions.php に以下のようなコードを追加することで、管理画面からのリクエストに対して言語パラメータの付与を抑制できる。

add_filter( 'rest_dispatch_request', function( $dispatch_result, $request, $route, $handler ) {
    // 管理画面からの REST API リクエストの場合、Bogo の言語処理をスキップ
    if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST && strpos( $route, '/wp/v2/' ) === 0 ) ) {
        remove_filter( 'rest_dispatch_request', 'bogo_rest_dispatch_request', 10 );
    }
    return $dispatch_result;
}, 5, 4 );

このコードは、/wp/v2/ から始まる REST API ルート(ブロックエディターが使用する主要なエンドポイント)に対して、Bogo が持つ bogo_rest_dispatch_request フィルターを一時的に除去する。ただし、この方法は Bogo の内部実装に依存しているため、プラグインのバージョンアップによって動作が変わる可能性がある点に注意が必要だ。

プラグインのダウングレードまたはフォーク版の利用を検討する

Bogo 3.9.2 で問題が顕在化したのであれば、1つ前のバージョンである 3.9.1 にダウングレードすることで問題が回避できる可能性がある。ただし、ダウングレードはセキュリティ上のリスクを伴うため、あくまで開発者側の対応を待つ間の暫定策と位置づける。

代替の多言語プラグインへの移行を検討する

Bogo はシンプルな多言語化プラグインとして長く使われているが、ブロックエディターとの相性問題が続くようであれば、Polylang や WPML、TranslatePress といった代替プラグインへの移行も選択肢に入る。これらのプラグインはブロックエディターとの互換性テストがより積極的に行われており、多言語サイトの構築で実績も豊富だ。

デバッグモードで詳細なエラー情報を取得する

デバッグモードで詳細なエラー情報を取得する

REST API の 500 エラーは、通常の PHP エラーとは異なり debug.log に記録されない場合がある。そのため、wp-config.php に以下の定数を追加して、より詳細なエラー情報を取得する。

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

さらに、ブラウザの開発者ツールで「ネットワーク」タブを開き、500 エラーを返している REST API リクエストを特定する。該当するリクエストの「レスポンス」タブを確認すると、サーバーから返された HTML のエラーページや JSON エラーオブジェクトが表示される。WordPress 7.0 では「このサイトで重大なエラーが発生しました」というメッセージが返ってくることが多い。

どうしてもエラーの詳細が取得できない場合は、wp-config.php に以下のコードを追加し、REST API エラー専用のログファイルを作成する方法もある。

add_action( 'rest_api_init', function() {
    set_error_handler( function( $errno, $errstr, $errfile, $errline ) {
        $log = sprintf( '[%s] %s:%d %s', date( 'Y-m-d H:i:s' ), $errfile, $errline, $errstr );
        file_put_contents( WP_CONTENT_DIR . '/rest-api-errors.log', $log . PHP_EOL, FILE_APPEND );
    });
}, 1 );

このコードは REST API の初期化時にカスタムエラーハンドラを登録し、発生したエラーをすべて wp-content/rest-api-errors.log に記録する。問題が解決したら必ず削除すること。

よくある質問

Bogo の代わりに Polylang を使っても同様のエラーは出るか

Polylang は REST API との統合が設計段階から考慮されており、ブロックエディターとの組み合わせでも同様の 500 エラーが発生する可能性は極めて低い。実際に多くの多言語サイトで Polylang とブロックエディターの組み合わせが問題なく運用されている。移行を検討する価値は十分にある。

この問題は WordPress 7.0 以前のバージョンでも発生するのか

WordPress 6.x 系では報告が少なく、7.0 へのアップデート後に顕在化したケースが多い。ブロックエディターの内部実装が 7.0 で変更され、特定の REST API エンドポイントに対するリクエストのタイミングやパラメータの扱いが変わったことが影響していると考えられる。

クラシックエディターに切り替えた後、再びブロックエディターに戻せるのか

問題なく戻せる。クラシックエディターで作成した投稿は、ブロックエディターに戻した際に自動的にクラシックブロックとして読み込まれる。Bogo プラグイン側のアップデートで問題が修正されたら、クラシックエディタープラグインを無効化してブロックエディターに戻せばよい。

REST API のエラーはフロントエンドの表示にも影響するのか

今回の問題は管理画面のブロックエディター内に限定されており、公開済みサイトのフロントエンド表示には影響しない。カテゴリー一覧や投稿一覧の表示、多言語切り替え機能は通常どおり動作する。ただし、ブロックエディターでカテゴリーを選択・編集できないため、投稿の作成や編集作業に支障が出る。

functions.php にフィルターフックを追加する方法がわからない場合はどうすればよいか

最も安全な方法は、FTP クライアントまたはレンタルサーバーのファイルマネージャーを使い、子テーマの functions.php ファイルを編集することだ。操作に不安がある場合は、Code Snippets プラグインを利用して管理画面からコードを追加する方法もある。誤ったコードの追加はサイト全体に影響するため、必ず事前にバックアップを取得してから作業すること。

この記事のポイント

  • Bogo 有効時にブロックエディターのカテゴリーパネルが空になるのは、REST API への lang パラメータ付与が競合を起こすため
  • クラシックエディターに一時的に切り替えることで、即座に問題を回避できる
  • functions.php にフィルターフックを追加し、管理画面からの REST API リクエストに対して Bogo の言語処理を抑制する方法もある
  • 根本解決には Bogo プラグイン側のアップデートが必要で、状況によっては代替プラグインへの移行も検討する
  • REST API の 500 エラーは debug.log に記録されないことがあるため、専用のエラーログ取得を設定すると原因特定が早まる
WooCommerceのメールが届かない時はWP Mail SMTPの「Force From Email」を確認

WooCommerceのメールが届かない時はWP Mail SMTPの「Force From Email」を確認

WP Mail SMTPのテストメールは届くのに、WooCommerceの注文確認や処理完了のメールだけが届かない場合、原因のほとんどはWP Mail SMTPで「Force From Email(送信元アドレスを強制)」の設定が無効になっていることだ。この設定を有効にし、WooCommerce側の送信元アドレスも確認すれば、数分で解決する。

なぜテストメールは届くのにWooCommerceのメールだけ届かないのか

なぜテストメールは届くのにWooCommerceのメールだけ届かないのか

WP Mail SMTPのテストメール機能は、管理画面から手動で送信した単体のメールだ。このとき、WP Mail SMTPは自分が設定されたSMTPサーバー情報(サーバー名、ポート番号、ユーザー名、パスワード)と認証用のメールアドレスを使ってメールを送る。テストが成功しているということは、SMTPサーバーとの通信自体は正常で、認証情報も間違っていない。

一方、WooCommerceが自動で生成するメール(新規注文、処理中、完了など)は、SMTPサーバーに直接接続するわけではない。内部的にWordPressのwp_mail()関数を呼び出し、WP Mail SMTPがそれをフックしてSMTP経由で配送する。この過程で問題になるのが送信元(From)アドレスの不一致だ。

多くのSMTPサービス(SendGrid、Gmail SMTP、Microsoft 365など)は、なりすまし防止のため、メールのFromヘッダーが認証済みのアドレスと一致しているか厳しくチェックする。WooCommerceはデフォルトで「wordpress@あなたのドメイン」のようなアドレスを送信元に設定するが、これがSMTP認証に使ったアドレスと違うと、SMTPサーバー側で送信が拒否される。テストメールはWP Mail SMTPが認証アドレスを直接使うので届く。ここが分かれ目だ。

Before(不一致=届かない)
WP Mail SMTP認証 admin@example.com
WooCommerce送信元 wordpress@example.com
SMTPサーバーが送信を拒否 認証アドレスとFromアドレスが異なるため
After(Force From Email有効=届く)
WP Mail SMTP認証 admin@example.com
WooCommerce送信元 admin@example.com 強制一致
SMTPサーバーが正常に配送 認証アドレスとFromアドレスが一致
不一致で拒否される状態  Force From Emailで解決

上の図のように、WP Mail SMTPの認証アドレスとWooCommerceが使う送信元アドレスが異なると、SMTPサーバーは「このメールのFromは本当に認証された持ち主か?」と判断できず、配送を止めてしまう。解決にはWP Mail SMTP側でこの不一致を強制的に揃える設定が必要になる。

WP Mail SMTPの「Force From Email」を有効にする手順

WP Mail SMTPの「Force From Email」を有効にする手順

まず試すべきは、WP Mail SMTPの設定画面にある「Force From Email」オプションを有効にすることだ。この設定は、WooCommerceを含むすべてのプラグインが生成するメールの送信元アドレスを、WP Mail SMTPに登録した認証アドレスで上書きする働きを持つ。これにより、SMTPサーバーがアドレスの不一致でメールを拒否する問題が解消される。

STEP 1 WordPress管理画面の「WP Mail SMTP」→「設定」を開く
STEP 2 「From Email」セクションまでスクロールする
STEP 3 「Force From Email」のチェックボックスをオンにする
STEP 4 画面下部の「設定を保存」ボタンを押す
STEP 5 WooCommerceのメール送信テストを実行して確認する

「Force From Email」が表示されない場合の確認ポイント

WP Mail SMTPの無料版(Free)には「Force From Email」のオプションが存在しないバージョンもある。設定画面の「From Email」セクションに項目が見当たらない場合は、以下の点を確認する。

  • WP Mail SMTPが最新バージョンに更新されているか
  • 有料版(Pro)を使っているか、無料版で機能が制限されていないか
  • 「From Email」欄に認証アドレスと完全に同じメールアドレスを手動で入力しているか

無料版で「Force From Email」が使えない場合は、「From Email」欄にSMTP認証で使っているアドレスをそのまま手入力し、さらに後述のWooCommerce側の送信元設定も同じアドレスに揃える方法で対応できる。

WooCommerce側の送信元アドレス設定も揃える

WooCommerce側の送信元アドレス設定も揃える

WP Mail SMTPの「Force From Email」が有効でも、設定が競合したり予期しない挙動でうまくいかないケースがある。念のため、WooCommerce自体のメール送信元設定もSMTP認証アドレスに揃えておくと確実だ。

WooCommerceの「差出人アドレス」を変更する

管理画面の「WooCommerce」→「設定」→「メール」タブを開く。ページ上部に「差出人アドレス(From Address)」という項目がある。ここにWP Mail SMTPで認証したメールアドレスとまったく同じアドレスを入力する。デフォルトではドメイン名から自動生成されたアドレスが入っていることが多いので、上書きする。

同じ画面のすぐ上にある「差出人(From Name)」はショップ名など任意の表示名でかまわない。ここは認証とは関係なく、受信者のメールソフト上で「誰からのメールか」として表示されるだけだ。

個別のメールテンプレート設定は通常変更不要

「メール」タブの下部には「新規注文」「処理中」「完了」など個別のメール通知一覧がある。ここで各メールの「受信者アドレス」を設定できるが、送信元アドレスを個別に指定する項目は標準ではない。そのため、通常は上部の「差出人アドレス」だけ修正すれば十分だ。もし個別テンプレートをカスタマイズするプラグインを入れている場合は、そのプラグイン側でFromアドレスが上書きされていないか確認する。

その他の確認ポイント

その他の確認ポイント

WooCommerceからテストメールを送る方法

WP Mail SMTPのテストメールだけでなく、WooCommerce側からもメール送信をトリガーして確認したい場合は、管理画面の「WooCommerce」→「ステータス」→「ツール」タブを開き、「メールをテスト」機能を使う。ここで任意のメール種別(例「新しい注文」)を選んで「送信」ボタンを押すと、実際のWooCommerceメールが送信される。Force From Emailの設定後、このテストで届くかどうかを見るのが最も確実だ。

プラグインの競合を疑う

稀に、他のSMTPプラグインやメール関連プラグイン(メールテンプレートカスタマイザー、メールログプラグインなど)が共存していると、WP Mail SMTPのフックより先にメール処理を横取りしてしまうことがある。「Force From Email」とWooCommerce側の設定を合わせても改善しない場合は、以下の手順で切り分けを行う。

  1. WP Mail SMTP以外のメール関連プラグインをすべて無効化する
  2. 標準テーマ(Twenty Twenty-Fiveなど)に一時的に切り替える
  3. WooCommerceの「メールをテスト」で再度送信を試す

ここで届くようになれば、テーマかプラグインのどちらかに原因がある。1つずつ再有効化して原因を特定する。

SMTPサーバー側の送信ログを確認する

上記すべてを試しても解決しない場合、SMTPサーバー側でメールがどう処理されているかを確認する。SendGridやGmail SMTP、Microsoft 365など、利用しているSMTPサービスには管理画面があり、送信ログやアクティビティログを確認できる。WooCommerceが送信を試みた形跡があるか、エラーが出ているかを見ることで、問題の所在がWP Mail SMTPより先か後かを切り分けられる。

よくある質問

「Force From Email」を有効にしてもメールが届かない場合は?

WooCommerce側の「差出人アドレス」が認証アドレスと一致しているか再度確認する。また、WP Mail SMTPの「Force From Name」も併せて有効にすると、名前の不一致によるフィルタリングを回避できることがある。それでも改善しなければ、他のメール関連プラグインを無効化して競合を確認する。

SMTP認証のメールアドレスはどのアドレスを使うべきか

自社ドメイン(例 info@自社ドメイン.com)を使うのが最も信頼性が高い。Gmailの無料アカウントでも送れるが、1日の送信制限があり、ビジネス用途ではGoogle WorkspaceやSendGridなどの専用SMTPサービスが推奨される。いずれの場合も、認証に使ったアドレスと完全に同じものを送信元アドレスとして使う必要がある。

迷惑メールフォルダに入ってしまう場合はどうするか

SMTP認証を使っていても、SPFレコードやDKIM署名がドメインのDNSに正しく設定されていないと、迷惑メールに分類されることがある。WP Mail SMTPの設定画面から「メールテスト」を送った際に表示される診断結果で、SPFやDKIMの状態を確認できる。これらが未設定または失敗している場合は、利用しているSMTPサービスの指示に従ってDNSレコードを追加する。

この記事のポイント

  • WP Mail SMTPのテスト成功はSMTP通信が正常な証拠で、問題は送信元アドレス不一致にある
  • 「Force From Email」を有効にすれば、全プラグインの送信元アドレスが認証アドレスに強制統一される
  • WooCommerce側の「差出人アドレス」設定も同じ認証アドレスに手動で揃えるとさらに確実
  • 改善しない場合はメール関連プラグインの競合やSMTPサーバー側のログを確認する
  • SPFやDKIMのDNS設定も合わせて確認すると、迷惑メール対策まで完結する
REST APIに非ログイン状態でアクセスできなくなった時の原因と解決手順

REST APIに非ログイン状態でアクセスできなくなった時の原因と解決手順

プラグインや本体のアップデートを機に、外部サービスからのREST APIリクエストが「Only authenticated users can access the REST API.」というエラーで拒否されるようになった場合、多くのケースではプラグインの認証設定が更新によって変更されている。まずは該当プラグインの「REST APIアクセスを許可する」設定を見直し、それでも改善しなければバージョン固有の不具合を疑う。

なぜアップデート後にREST APIが突然使えなくなるのか

なぜアップデート後にREST APIが突然使えなくなるのか

WordPressのREST APIは、外部アプリやサービスとサイトがデータをやり取りするための共通の窓口だ。決済ゲートウェイの通知(ウェブフック)、モバイルアプリからの記事取得、別サーバーとの在庫連携など、多様な自動処理がREST APIを通じて動いている。

プラグインのバージョンアップでアクセスが遮断される原因は、大きく分けて二つある。ひとつはセキュリティ強化を目的とした仕様変更で、非ログインユーザー(未認証リクエスト)に対する制限が新たに追加、あるいは既定で有効化されたケースだ。もうひとつは、アップデート時のコードの不具合で「REST APIを許可する」設定が内部的に無視されてしまうケースである。

REST API遮断の主な発生パターン
ケースA セキュリティ機能の新設・既定値変更
新バージョンで「未認証ユーザーのREST APIアクセスをブロック」が既定でオンになった
ケースB バージョン固有のコード不具合
管理画面の設定は「許可」のままでも内部処理が効かず拒否される
仕様変更による遮断  不具合による遮断

いずれの場合も、ウェブフックを受け取るサイト側では「ログインしていない外部からのPOSTリクエスト」として扱われるため、認証エラーが返ってしまう。ECサイトの決済通知や予約システムの在庫更新など、リアルタイム性が求められる連携ほど被害が大きい。

プラグイン設定でREST APIのアクセス制御を確認する

プラグイン設定でREST APIのアクセス制御を確認する

最初に行うべきは、該当プラグインの設定画面にREST API関連の項目が存在するかどうかの確認だ。多くのセキュリティ系プラグインやユーザー管理プラグインには「REST APIへのアクセスを制限する」「未認証ユーザーをブロックする」といったチェックボックスが用意されている。

管理画面から該当プラグインの設定ページを開き、「REST API」「APIアクセス」「外部リクエスト」「認証」などのキーワードを含む項目を探す。もし「未認証ユーザーのREST APIアクセスを無効にする」といった設定がオンになっていれば、これをオフに切り替えて保存し、外部からのリクエストが再び通るかをテストする。

設定項目の名称や位置はプラグインによって異なる。セキュリティタブの中にあったり、詳細設定の一番下に隠れていたりすることも多い。見つからない場合はプラグインのドキュメントや公式サポートフォーラムで「REST API permission」をキーに検索する。

設定確認から解決までのフロー
STEP 1 プラグイン設定でREST API許可のチェックボックスを探す
STEP 2 無効化されていればONに変更して保存
STEP 3 外部からAPIリクエストを送信して動作確認
STEP 4 改善しなければバージョンの切り戻しを検討

プラグインのバージョンを切り戻して検証する

プラグインのバージョンを切り戻して検証する

設定が正しく「許可」になっているにもかかわらずAPIが機能しない場合、プラグイン自体の不具合を疑う段階に入る。管理画面上は許可しているように見えて、内部的な処理では設定値を正しく読み取れていない可能性がある。

まずは該当プラグインの安定していた旧バージョンを入手し、手動でインストールし直す。公式プラグインディレクトリの「以前のバージョン」セクションや、プラグイン開発者がGitHubでリリースしているアーカイブからダウンロードできる。

切り戻しは次の手順で進める。プラグイン一覧画面で問題のプラグインを一度無効化し、削除する(設定データは残るため心配は不要)。続いて旧バージョンのZIPファイルを「プラグイン」→「新規追加」→「プラグインのアップロード」からインストールし有効化する。この状態で外部からのAPIリクエストが正常に処理されるかテストし、復旧を確認したら開発元に不具合報告を送る。

どうしても旧バージョンが入手できない場合は、WP Rollbackプラグインを使って管理画面から直接ダウングレードする方法もある。ただし本番サイトでの使用は慎重に行い、必ず事前にバックアップを取得しておく。

特定エンドポイントだけを許可するカスタム対応

特定エンドポイントだけを許可するカスタム対応

セキュリティ上の理由からREST API全体を無制限に開放したくない場合は、必要なエンドポイントだけを選択的に許可する方法が有効だ。たとえば決済ゲートウェイのウェブフックは特定のルート(/wp-json/wc/v3/ordersなど)だけ通ればよい。

テーマのfunctions.phpに以下のようなフィルターを追加すれば、特定のRESTルートに対して認証要件を緩和できる。コードを直接書く場合は必ず子テーマを利用する。

add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! empty( $result ) ) {
        return $result;
    }
    if ( strpos( $_SERVER['REQUEST_URI'], '/wp-json/my-plugin/v1/webhook' ) !== false ) {
        return true;
    }
    return $result;
});

このコードは、指定したパス(上の例では/my-plugin/v1/webhook)へのアクセスに対して認証チェックをスキップし、それ以外のエンドポイントは通常の認証を維持する。プラグイン本体を修正せずに済むため、アップデートが来ても上書きされる心配がない。

フィルターを追加した後は必ず、許可したエンドポイントに外部からcurlコマンドやPostmanでテストリクエストを送り、意図したとおりに動作することを確認する。想定外のエンドポイントが開放されていないかも併せてチェックする。

リバースプロキシやWAFがリクエストを遮断していないか調べる

リバースプロキシやWAFがリクエストを遮断していないか調べる

プラグインの設定もバージョンも問題ないのにAPIが機能しない場合、サーバー環境側でリクエストが遮断されている可能性がある。CDNのWAF(ウェブアプリケーションファイアウォール)、ホスティング側のセキュリティモジュール、あるいは.htaccessの記述が原因で、外部からのPOSTリクエストがブロックされているケースは意外に多い。

確認すべきはログだ。WAFを導入している場合はその管理画面で遮断ログを検索し、APIリクエストが誤検知でブロックされていないか調べる。サーバーのアクセスログでは、対象のエンドポイントにリクエストが到達しているかどうか、到達している場合のHTTPステータスコード(401や403なら認証・権限の問題、200系ならアプリケーション側で正常処理後にエラーが発生している)をチェックする。

とくに管理画面のURLを変更するプラグインや、xmlrpc.phpを無効化する設定が、間接的にREST APIのエンドポイントにまで影響を与えていることもある。これらの設定も一時的に解除してテストを行う。

よくある質問

どのプラグインがREST APIに影響を与えているか特定するには

全プラグインを一度無効化し、問題のエンドポイントに外部からアクセスして正常応答を確認する。その後、プラグインを1つずつ有効化しながら再テストすれば、原因のプラグインを絞り込める。テーマのfunctions.phpのカスタムコードも疑わしい場合は、標準テーマに一時的に切り替えて検証する。

外部サービスが受け取るエラーの内容を詳しく知るには

WordPressのREST APIは認証エラー時にJSON形式のエラーオブジェクトを返す。外部サービス側でHTTPレスポンスボディをログに残せるなら、codemessageの値を取得すれば原因の手がかりになる。ログが取れない場合は、curlで手動リクエストを送り、curl -vでレスポンスボディを直接確認する。

REST API全体を無効化せずにセキュリティを保つ方法はあるか

特定のIPアドレスからのみアクセスを許可する.htaccessの設定、APIキーやアプリケーションパスワードを使った認証の義務付け、あるいは必要なエンドポイントだけをホワイトリスト登録するカスタムコードで対応できる。無制限の全面開放は避け、必要最小限の権限に絞ることが安全面でも推奨される。

プラグインをダウングレードしても問題はないのか

セキュリティ修正や脆弱性対策を含むアップデートを巻き戻すことになるため、ダウングレードはあくまで一時的な回避策と位置づける。復旧を確認したら速やかに開発元へ報告し、修正バージョンがリリースされたらすぐに更新する。ダウングレード期間中はサイト全体の監視を強化する。

アップデート前のバージョンが不明な場合はどうするか

プラグイン一覧画面の「詳細を表示」から「開発」タブを開くと、過去のバージョン履歴が参照できる。または公式プラグインディレクトリの「Advanced View」に「Previous Version」のリンクが用意されている。どうしてもわからない場合は、バックアップから前回正常に動作していたプラグインファイルを復元する。

この記事のポイント

  • プラグイン更新後にREST APIが遮断されたら、まず設定画面のアクセス制御項目を確認する
  • 設定が正しくても動かない場合は、旧バージョンに切り戻して不具合を検証する
  • 必要なエンドポイントだけをfunctions.phpのフィルターで選択的に開放できる
  • WAFやサーバー設定がリクエストをブロックしていないかログで確認する
  • ダウングレードは一時的な対策とし、修正版のリリースを待って更新する
WPManageNinjaプラグイン更新で不正コード混入 全亜種を検出するSQLと駆除手順

WPManageNinjaプラグイン更新で不正コード混入 全亜種を検出するSQLと駆除手順

WPManageNinja のプラグインを更新したら不正なコードが紛れ込んだ場合、最も確実な検出方法はデータベースのオプション値を直接検索することだ。apii.observer というドメイン名を探す SQL クエリを実行すれば、影響を受ける全13プラグインの亜種を一網打尽にできる。

なぜ通常のプラグイン更新でバックドアが入り込んだのか

なぜ通常のプラグイン更新でバックドアが入り込んだのか

2026年7月31日、WordPress 用プラグインを多数提供する WPManageNinja 社の旧アップデートサーバーが侵害された。同社は以前に販売プラットフォームを移行しており、本来は停止しているはずの旧サーバーが生き残り、かつプロキシが一部の更新トラフィックをそちらに転送し続けていた。この時間帯に管理画面で「更新」ボタンを押したユーザーは、正規の更新チャネルを通じて悪意あるパッケージを受け取ってしまったのだ。

パスワード突破でも脆弱性攻撃でもなく、ただの更新作業が侵入口になった。このサプライチェーン攻撃の怖さは、更新ボタンを押したこと自体はまったく正常な運用であり、疑いようがない点にある。

影響を受ける13のプラグインを確認する

影響を受ける13のプラグインを確認する

WPManageNinja 社が公開したインシデント対応資料には13のプラグインプロファイルが含まれている。一方、当初の告知では一部しか公表されていなかった。注意すべきなのは以下の全リストだ。

  • azonpress
  • fluent-affiliate-pro
  • fluent-boards-pro
  • fluent-booking-pro
  • fluent-community-pro
  • fluent-player-pro
  • fluent-support-pro
  • fluentcampaign-pro(FluentCRM)
  • fluentform-signature
  • fluentformpro
  • ninja-tables
  • wp-payment-form-pro(Paymattic)
  • wp-social-ninja-pro

これら13種類のいずれかを利用しているサイトは、更新履歴の有無にかかわらず直ちに調査が必要だ。WPManageNinja 社からドメインリストがメールで送られていたとしても、それを鵜呑みにしてはいけない。実際に、リストに載っていないサイトからも感染が確認されている。

侵入されたサイトに見られる具体的な症状と隠蔽の仕組み

侵入されたサイトに見られる具体的な症状と隠蔽の仕組み

バックドアは、正規プラグインのフォルダ内に PHP ファイルを1つ追加し、既存のファイルの末尾に小さなローダーコードを追記する形で設置される。Fluent Forms Pro の例では、以下のようになっていた。

Before(感染状態)
fluentformpro/libs/ に class-license-sync.php(39,743バイト)が存在
fluentformpro.php の22〜24行目に不正な require_once とクラス呼び出しが追記
After(駆除後)
正規のプラグインファイルのみ存在し、不正ファイルは削除済み
fluentformpro.php の行数がクリーンな状態に戻っている
感染状態   駆除後

このデモは Fluent Forms Pro におけるバックドアの有無を視覚化したものだ。

データベースには _wp_update_meta_cache_site_transient_update_meta といったオプション名が書き込まれる。これらの名称は WordPress コアが使う一時データ(Transient)に酷似しており、ひと目見ただけでは異常と気づきにくい。オプションの値には攻撃者のコマンド&コントロールサーバーである apii.observer が含まれ、さらにサイト固有のトークンとログインキーが保存されていた。このログインキーはパスワードなしで WordPress 管理画面にログインできる「万能鍵」であり、ファイルを削除するだけでは不正アクセスのリスクは消えない。

全亜種を一発で検出するデータベースクエリ(WP-CLI)

全亜種を一発で検出するデータベースクエリ(WP-CLI)

63個のオプション名や26個の cron フックを個別に調べる必要はない。すべての亜種に共通する特徴は、C2 サーバーアドレス apii.observer をオプションの値として持っていることだ。したがって、次の1行のクエリで全13プラグインの感染を一括検出できる。

PREFIX=$(wp db prefix)
wp db query "SELECT option_name FROM ${PREFIX}options \
WHERE option_value LIKE '%apii.observer%'" --skip-column-names

cron ジョブまで同時に調べたい場合は以下のように拡張する。

wp db query "SELECT option_name FROM ${PREFIX}options \
WHERE option_value LIKE '%apii.observer%' \
OR option_value LIKE '%wp_update_check_schedule%'" --skip-column-names

wp cron event list --fields=hook,next_run_relative \
| grep -E "wp_update_check_schedule|wp_license_verify_schedule"

このアプローチの本質は「マルウェアが自らのサーバーと通信しなければならない」という不変の事実を突く点にある。シグネチャリストは古くなるが、通信先のドメインはそう簡単には変わらない。覚えておいて損はない手法だ。

sFTP しか使えない場合のファイルチェック方法

sFTP しか使えない場合のファイルチェック方法

レンタルサーバーによっては SSH が提供されず、WP-CLI も使えないことがある。その場合は sFTP 経由でファイルを確認する。Python の paramiko ライブラリを使った検出スクリプトが有効だが、重要なのは「確実に読めたと言える状態だけをクリーンと判定する」ことだ。

STEP 1 sFTP で接続し、プラグインフォルダにアクセスできるか確認する
STEP 2 class-license-sync.php や NinjaTableDataSync.php が存在するか確認
STEP 3 ローダーが追記される fluentformpro.php などに不正マーカーが含まれるかテキスト検索
STEP 4 フォルダが存在したのに読み取れなかった場合は「CLEAN」と判定せず、必ず「ERROR」を返す

この判定フローは、読み取り失敗を「感染していない」と誤認させないための安全策だ。

より確実な方法として、販売元のアカウントからクリーンなプラグイン ZIP をダウンロードし、サーバー上のファイル群とファイルサイズを比較する手段もある。手元のクリーンコピーに存在しないファイルや、サイズが異なるファイルがあれば、それが不正コードの証拠になる。

安全かつ完全な駆除手順(ファイルとデータベースの順序が重要)

安全かつ完全な駆除手順(ファイルとデータベースの順序が重要)

駆除で最も失敗しやすいのが「データベースから先に削除する」手順だ。残ったファイルの cron が再度データベースに不正な行を書き込んでしまう。必ず以下の順序で実施する。

1. 感染したプラグインフォルダを削除し、クリーンな ZIP から再インストールする

wp plugin delete fluentformpro
wp plugin install /path/to/fluentformpro-clean.zip --activate
wp plugin get fluentformpro --field=version

バージョン番号を必ず確認し、6.2.8 や 6.2.9 といったアップデータ経由の古い番号が表示されたら、ZIP からの再インストールが正しく行われていない可能性がある。

2. データベースから不正なオプションと cron を削除する

PREFIX=$(wp db prefix)
# まず内容を確認
wp db query "SELECT option_name FROM ${PREFIX}options \
WHERE option_value LIKE '%apii.observer%'"
# 削除実行
wp db query "DELETE FROM ${PREFIX}options \
WHERE option_value LIKE '%apii.observer%'"
# cron イベントも削除
wp cron event delete wp_update_check_schedule
wp cron event delete wp_license_verify_schedule

3. ソルトを変更し、すべてのセッションを無効化する

wp config shuffle-salts で wp-config.php に定義されたソルト(8つのキー)を新しい値に置き換える。これにより、攻撃者が入手したログインキーを含むすべての既存セッションが強制ログアウトされる。

wp config shuffle-salts

その後、管理者パスワードを手動で変更する。ソルトの更新はパスワードそのものを上書きしないからだ。

4. 駆除後は状態を読み取って必ず検証する

削除コマンドの成功メッセージを信用してはいけない。cron 削除が正常に受け付けられても、実際には実行されずにスケジュールが残っているケースがある。再度クエリを実行し、返却行数がゼロであることを目視確認する。

wp db query "SELECT option_name FROM ${PREFIX}options \
WHERE option_value LIKE '%apii.observer%'" --skip-column-names
# 出力が完全に空であることを確認
wp cron event list --fields=hook,next_run_relative \
| grep -E "wp_update_check_schedule|wp_license_verify_schedule"
# 同じく出力が空であることを確認

最後に wp option get blogname やサイトのトップページ表示で WordPress が正常に起動していることを確かめる。

WP-CLI が使えない環境でのソルト変更と安全策

WP-CLI が使えない環境でのソルト変更と安全策

レンタルサーバーの制限や独自コネクターの仕様で wp config shuffle-salts が使えない場合は、FTP 経由で wp-config.php を直接編集する。このとき、次の点を徹底する。

  • 現在の wp-config.php を必ずローカルにバックアップする。
  • WordPress.org のソルト生成 API から新しい値を取得し、8つの define 文すべてを置換する。
  • 8つすべてを見つけられなかった場合は作業を中断する。部分的な置換はサイトを破壊する。
  • 置換後のファイルサイズが数百バイト以上変化していないか確認する。
  • アップロード後にサーバーからファイルを読み戻し、意図した内容かをバイト単位で比較する。
  • データベースパスワードを含むため、ファイル内容をログやターミナルに絶対に出力しない。

複数サイトをスクリプトで一括処理する場合は、1サイトごとに別プロセスで実行し、数秒の待機を挟む。連続したリクエストはサーバーのアンチボット機能にブロックされる原因になる。HTTP 202 や 429 が返ったら即座に全処理を停止する。

よくある質問

プラグインを更新していないのに感染する可能性はあるか

今回の経路は更新操作に限られる。ただし、過去に更新したタイミングが問題の時間帯と重なっていれば、更新していないつもりでも感染している場合がある。cron による自動更新が有効なら、手動更新していなくても該当する。

wp-config.php のソルトを変更するとどうなるか

そのサイトにログインしているすべてのユーザーが強制的にログアウトされる。パスワードは変わらないため、同じパスワードで再ログインは可能だ。「Remember Me」で保存されたセッションも無効になる。

感染したかどうか管理画面から判断できるか

見た目にはまったく変化がない。管理画面の表示や動作に異常が出ないよう設計されているため、プラグイン一覧や更新画面から気づくことはほぼ不可能だ。

データベースのバックアップから復元しても大丈夫か

バックアップの中に不正オプションが含まれていれば、復元で再感染する。リストア前に必ずバックアップの SQL を確認し、apii.observer を含む行がないか検索しておく必要がある。

WAF やセキュリティプラグインで防げたか

この攻撃は正規の更新チャネルを経由しているため、一般的な WAF やマルウェアスキャナーでは検知できない。実際に複数のセキュリティプラグインが稼働している状態でも、バックドアファイルを無害と判断した事例が報告されている。今回の経験から、セキュリティプラグインの「異常なし」を鵜呑みにしないことが重要だ。

この記事のポイント

  • WPManageNinja の当該13プラグインを利用しているサイトは、更新の有無にかかわらず即座に調査する。
  • 全亜種の検出は apii.observer を含むオプション値を SQL で LIKE 検索するのが最速かつ確実。
  • 駆除は「プラグインフォルダの再インストール」→「データベース削除」→「ソルト変更とパスワード変更」の順序厳守。
  • 削除後は成功メッセージを信じず、再度クエリを実行してゼロ件を目視確認する。
  • ソルト変更だけではパスワードは変わらない。管理者パスワードも忘れずに変更する。
Premium Addonsの更新で重大なエラーが出た時の原因と対処法

Premium Addonsの更新で重大なエラーが出た時の原因と対処法

Premium Addons for Elementor の更新後に「このサイトで重大なエラーが発生しました」と表示されサイトが落ちる場合、原因は更新パッケージのファイル欠損や破損にある。is_widget() メソッドが見つからないエラーがログに記録されているなら、プラグインの手動再インストールで解決する可能性が高い。

なぜ Premium Addons の更新で致命的エラーが起きるのか

なぜ Premium Addons の更新で致命的エラーが起きるのか

Premium Addons 4.11.91 から 4.11.93 への更新中に「このサイトで重大なエラーが発生しました」が表示されるケースでは、エラーログに Call to undefined method PremiumAddons\Modules\Woocommerce\Module::is_widget() が記録される。

このエラーは、WordPress の自動更新や管理画面からのワンクリック更新を実行した際に、プラグインのファイル一式が完全に展開されず、一部の PHP ファイルが欠損した状態でバージョンだけが切り替わった場合に発生する。module-base.phpis_widget() メソッドを呼び出そうとしたタイミングで、その定義が存在せず PHP が致命的エラーを返す仕組みだ。

この種のエラーは Premium Addons に限らず、大規模なアドオン系プラグインの更新時に時折見られる。サーバーの実行時間制限やメモリ不足が引き金になることもあるが、今回は開発元が更新パッケージの不備を認めて修正版を再提供している。つまり原因は利用者側の環境ではなく、配信された更新ファイル自体の不備だ。

Before(エラー発生時)
管理画面から Premium Addons 更新 重大エラー
Error: Call to undefined method
PremiumAddons\Modules\Woocommerce\Module::is_widget()
After(修正後)
手動で 修正済み ZIP をアップロード 更新成功
WooCommerce モジュールが正常に読み込まれ、エラーログにも記録なし
エラー状態  修正後

このデモは、ファイル欠損が原因で起こる典型的なエラーパターンとその解消後の状態を示している。

手動でプラグインを再インストールする手順

手動でプラグインを再インストールする手順

自動更新でエラーが起きた場合、有効な解決策は修正版の ZIP ファイルを入手し手動でアップロードすることだ。以下の手順で進める。

STEP 1 Premium Addons の公式サイトまたは WordPress.org のプラグインページから最新の ZIP ファイルをダウンロードする
STEP 2 WordPress 管理画面の「プラグイン」→「新規追加」→「プラグインのアップロード」から ZIP を選択
STEP 3 「今すぐインストール」を実行し、既存のプラグインを上書きすることを確認
STEP 4 プラグインを有効化し、サイトキャッシュを全削除して動作を確認

手動アップロードによる上書き更新は、ファイルの破損や欠損を確実に修復できる方法だ。

公式サイトから ZIP を入手する

Premium Addons は WordPress.org の公式プラグインディレクトリで配布されている。検索エンジンで「Premium Addons for Elementor WordPress」を検索し、プラグインページの「ダウンロード」ボタンから ZIP ファイルを取得する。有料版を使っている場合は、購入元のアカウントページから最新バージョンをダウンロードする。

管理画面から ZIP をアップロードする

「プラグイン」→「新規追加」を開き、ページ上部の「プラグインのアップロード」ボタンをクリックする。ファイル選択画面で先ほどダウンロードした ZIP を選び、「今すぐインストール」を押す。WordPress が「すでにインストールされています」と検出した場合、「現在のものをアップロードしたものに置き換える」という選択肢が出るのでそれを選ぶ。

キャッシュを完全にクリアする

プラグインの上書きが完了したら、サイトのキャッシュを徹底的に削除する。キャッシュ系プラグイン(W3 Total Cache や WP Super Cache など)の「全キャッシュ削除」機能を実行し、さらにブラウザのキャッシュもクリアする。サーバー側で Nginx FastCGI キャッシュや Redis オブジェクトキャッシュを使っている場合はそれらも合わせてクリアする。

それでもエラーが続く場合の追加対応

それでもエラーが続く場合の追加対応

エラーログの詳細を確認する

手動再インストール後もエラーが続くなら、まず WooCommerce のステータスログを開く。「WooCommerce」→「ステータス」→「ログ」タブから、fatal-errors で始まる最新のログを確認する。別のメソッドやファイルでエラーが出ている場合、プラグインの競合が原因である可能性が高い。

プラグイン競合の切り分けを実施する

Premium Addons 以外の全プラグインを一時的に無効化し、WordPress の標準テーマ(Twenty Twenty-Five など)に切り替える。その状態で Premium Addons だけを有効にしてエラーが再現するか確認する。ここで問題が解消すれば、無効化したプラグインの中に競合相手がいる。

開発元に修正版をリクエストする

公式リポジトリのバージョンでもエラーが解消しない場合は、Premium Addons のサポートフォーラムにエラーログ全文と環境情報(WordPress バージョン、PHP バージョン、Elementor バージョン)を添えて報告する。開発元が個別の修正パッケージを提供してくれることがある。

よくある質問

管理画面すら開けない状態でどうやって直せばいいか

FTP クライアントまたはレンタルサーバーのファイルマネージャーで /wp-content/plugins/premium-addons-for-elementor/ ディレクトリを一旦リネームする。これでプラグインが無効化され管理画面にアクセスできるようになる。その後、正しい ZIP を展開し直して元のディレクトリ名に戻し、管理画面から有効化する。

WooCommerce を無効にすればエラーは出なくなるのか

エラーの発生箇所が WooCommerce 用モジュールであるため、WooCommerce 本体を無効化すればこの特定のエラーは止まる。しかしショップ機能が完全に停止するため、恒久対応にはならない。あくまで緊急避難として認識し、速やかに Premium Addons の修正を行うべきだ。

自動更新を止めて手動更新に切り替えるべきか

Premium Addons に限って一時的に自動更新を無効化するのは有効な予防策だ。「プラグイン」画面で該当プラグインの「自動更新を有効化」のチェックを外せば、次回以降の更新は手動で制御できる。問題が完全に解決したと確認できた後に再度自動更新を有効化すればよい。

PHP のバージョンが原因ということはあるか

Premium Addons は PHP 8.3 に対応しているため、今回の is_widget() エラーは PHP バージョンに起因するものではない。ただし PHP 8.x 系ではメソッドの未定義エラーが例外ではなく致命的エラーとして扱われるようになったため、以前の PHP 7.x 系では警告で済んでいた問題がサイト停止に直結するようになっている。

この記事のポイント

  • Premium Addons 更新後の重大なエラーは、更新ファイルの欠損や破損で定義されていないメソッドを呼び出すのが原因
  • 手動で最新の ZIP ファイルをアップロードして上書きすれば解決する
  • キャッシュの全削除を忘れずに行う
  • 再発防止として自動更新の一時停止や更新前のバックアップが有効
  • FTP からのプラグイン無効化は管理画面にアクセスできないときの最終手段
PHP 8.5で(boolean)キャストの非推奨警告が出た時のWordPressでの対処法

PHP 8.5で(boolean)キャストの非推奨警告が出た時のWordPressでの対処法

PHP 8.5にバージョンアップしたWordPressサイトで「Non-canonical cast (boolean) is deprecated」という警告が表示されたら、(boolean)と書かれたキャストを(bool)に置き換えるだけで解消する。これはPHP 8.5で非正規のスカラー型キャストが非推奨になったためで、テーマやプラグインのコードを修正する必要がある。

PHP 8.5で非推奨になった(boolean)キャストとは

PHP 8.5で非推奨になった(boolean)キャストとは

PHPは長らく、変数の型を変換するために(boolean)(integer)といった別名のキャスト記法を受け入れてきた。しかしPHP 8.5から、これらの「正式でない(non-canonical)」表記は非推奨として扱われ、実行時にDeprecation警告が発生する。ブーリアン型へのキャストは(boolean)ではなく(bool)を、整数型は(integer)ではなく(int)を使うようPHP本体が求めるようになったのだ。

この変更は将来のバージョンで古い記法を完全に削除するための前段階で、今のうちに修正しないと、PHP 9.0以降で致命的エラーに変わる可能性がある。WordPressのテーマやプラグインのコードにこうした古いキャストが残っていると、サイトのエラーログに大量の警告が出力されたり、デバッグモードで画面に表示されたりする。

この警告がWordPressサイトで発生するケース

この警告がWordPressサイトで発生するケース

実際にWordPressでこの警告が出るのは、プラグインが原因であることがほとんどだ。たとえばカスタムフィールドを拡張する有名な「Pods」プラグインの古いバージョンでは、オートコンプリートフィールドの必須設定などを処理する部分で(boolean)キャストを使っており、PHP 8.5環境では次のような警告が発生する(実例を簡略化して示す)。

Deprecated: Non-canonical cast (boolean) is deprecated, use the (bool) cast instead in /var/www/example.com/wp-content/plugins/pods/classes/fields/pick.php on line 1113

同じ警告は、他のカスタムプラグインや古いテーマでも起こり得る。共通するのは「(boolean)」「(integer)」といったエイリアス表記がコード内に存在し、かつサーバーのPHPバージョンが8.5以上になっているという条件だ。PHP 8.4までなら問題なく動作していたサイトが、アップグレードした途端に警告まみれになる典型例といえる。

警告を解消するための具体的な対処法

警告を解消するための具体的な対処法

解決の根本は、警告が指摘するファイル内の(boolean)(bool)に書き換える一手間だけだ。ただし、プラグイン本体を直接編集するとアップデートで上書きされてしまうため、一時的な対処か、プラグイン開発者へ修正を依頼するのが本筋になる。ここではサイト管理画面からFTPやファイルマネージャーでアクセスできる場合の手順を示す。

Before(非推奨)
$ajax = (boolean) $field_data[‘autocomplete’];
After(修正後)
$ajax = (bool) $field_data[‘autocomplete’];

修正が必要なファイルと行を特定する

警告メッセージにはファイルのパスと行番号が明示されている。たとえば「/var/www/example.com/wp-content/plugins/pods/classes/fields/pick.php on line 1113」のように表示されるので、そのパスを頼りに該当ファイルを開く。サーバー上のパスはサイトのドキュメントルートからの絶対パスで示されるため、FTPクライアントやサーバー管理ツールのファイルマネージャーで同じディレクトリを探せばよい。

コードエディタで(boolean)(bool)に置換する

該当行を開いたら、まずバックアップを取った上で編集を始める。書き換えは極めて単純で、(boolean)という文字列を(bool)に置き換えるだけだ。同じファイル内に複数箇所ある可能性が高いので、エディタの検索機能を使って「(boolean)」をすべて検索し、該当行をまとめて修正すると確実に警告を一掃できる。もし(integer)(real)など他の非推奨キャストも見つかれば、それぞれ(int)(float)へ変更しておく。

修正後に動作確認とログのチェックを行う

ファイルを上書き保存したら、必ずWordPressのデバッグモードを有効にしてwp-config.phpdefine('WP_DEBUG', true);を設定し、サイトを数ページ表示して同種の警告が消えたことを確認する。デバッグモードを無効にしていてもサーバーのPHPエラーログには記録されるため、ログを監視している場合はそちらでも最終チェックを行う。修正が完了したら、デバッグモードは元に戻しておく。

プラグイン開発者向けの恒久対応と注意点

プラグイン開発者向けの恒久対応と注意点

自作プラグインの開発者や、クライアントワークで修正依頼を受ける制作者は、より根本的な対応を検討すべきだ。PHP 8.5の非推奨変更は、コード全体にわたって古いキャストが使われていないか一括でチェックする良い機会になる。

エディタの正規表現検索で「\(boolean\)」「\(integer\)」「\(real\)」「\(double\)」といったパターンを検索し、それぞれ(bool)(int)(float)(float)へ置き換えると効率的だ。なお(real)(double)はどちらも浮動小数点数型を意味するエイリアスで、いずれも(float)が正式なキャストになる。

ただし、プラグインの互換性を保つために、PHP 8.5専用のコードに一気に書き換えるのではなく、バージョン分岐と組み合わせる方法もある。if (version_compare(PHP_VERSION, '8.5', '>=')) {で新しいキャストを使い、それ以前は従来の記法を残すといった対応だ。とはいえ(bool)自体はPHP 4から存在する極めて古い正式キャストなので、事実上すべてのバージョンで動作する。互換性を気にする必要はほとんどない。

よくある質問

PHP 8.5以外のバージョンでもこの警告は出るのか

いいや、PHP 8.5で初めて「Non-canonical cast」の非推奨警告が導入された。PHP 8.4以下では(boolean)は問題なく動作し、警告も出ない。ただしPHP 9.0ではエラーに格上げされる見込みのため、早めに対処しておくと将来的に安全だ。

警告を放置してもサイトの動作に問題はないのか

現時点ではDeprecation警告であり、サイトの表示や動作が止まることはない。しかしデバッグモードがオンの場合、画面上部に警告が表示されてレイアウトが崩れたり、エラーログが膨大になってサーバーのディスクを圧迫する可能性がある。長期的にはPHPのバージョンアップでエラーになるため、放置は推奨しない。

プラグインのアップデートで自動的に修正されるのか

プラグイン開発者が修正をリリースすれば、アップデートするだけで警告は解消される。たとえばPodsプラグインでは既にこの問題が報告されており、近いバージョンで(bool)への書き換えが行われる可能性が高い。開発者にフィードバックを送ることも有効な手段だ。

警告を非表示にするだけの対処は可能か

wp-config.phpdefine('WP_DEBUG', false);にすれば管理画面やフロントエンドへの表示は止められる。ただしPHPのエラーログには記録され続けるため、根本解決にはならない。また、error_reportingを変更してDeprecationを抑制する方法もあるが、他の重要な非推奨警告も見逃すためおすすめできない。コードを修正するのが最も確実で手間も少ない。

子テーマや自作コードがない場合、どこを修正すればいいのか

該当するプラグインのファイルを直接編集しなければならないが、前述のとおりアップデートで上書きされるリスクがある。恒久的な対策としては、プラグインの開発者に修正を依頼するか、GitHubなどでプルリクエストを送るのが理想的だ。どうしてもすぐに警告を消したい場合は、修正後にプラグインの自動更新を停止しておき、次期バージョンで公式対応されるまで手動管理する手もある。

この記事のポイント

  • PHP 8.5で(boolean)キャストは非推奨になりDeprecation警告が出る
  • (boolean)(bool)に書き換えれば警告は消える
  • 警告メッセージのファイルパスと行番号を頼りに修正箇所を探す
  • 修正は単純な置換だがバックアップを取ってから行う
  • プラグイン本体の編集はアップデートで上書きされる点に注意
WPC Linked Variation 更新で管理画面の依存スクリプトエラーを修正する方法

WPC Linked Variation 更新で管理画面の依存スクリプトエラーを修正する方法

WooCommerceの商品バリエーションを扱うプラグイン「WPC Linked Variation」(WooCommerce用)を使っていると、管理画面のあらゆるページで「依存関係にあるスクリプトが登録されていません」という警告が表示される場合がある。これはバージョン4.4.3以前の不具合であり、最新版4.4.4以降へアップデートすればすぐに消える。

エラー「正しく呼び出されていません」の中身と発生原因

エラー「正しく呼び出されていません」の中身と発生原因
エラー状態
管理画面の任意のページで、「依存関係 wc-enhanced-select, selectWoo が登録されていない」という警告が表示される
正常状態
プラグイン更新後、または正しい画面チェック付きで読み込まれれば警告は消え、管理画面がすっきりする

上記のようなデモの流れで、管理画面の上部やQuery Monitorに突然エラーが出現する。

WooCommerceは商品編集画面や注文編集画面といった限定された管理ページにのみ、wc-enhanced-selectselectWooといった選択UIを拡張するためのスクリプトを登録している。ところがWPC Linked Variation 4.4.3は、admin_enqueue_scriptsアクションの中で画面を一切絞り込まずに、これらに依存するwpclv-backendを読み込もうとしていた。

その結果、WooCommerceがスクリプトを用意していない「割引プラグインの設定画面」や「ユーザープロフィール」など、まったく関係のないページで依存先が見つからず、WordPressが「WP_Scripts::add の呼び出しが正しくない」と警告を出す。フロントエンドの表示や動作には影響しないが、管理画面の見通しが悪くなり、Query Monitorなどのデバッグツールを使っていると特に目立つ。

プラグイン更新でエラーを消す手順

プラグイン更新でエラーを消す手順
STEP 1 WordPress管理画面「プラグイン」→「インストール済みプラグイン」へ移動する
STEP 2 「WPC Linked Variation for WooCommerce」に更新通知が出ていたら「今すぐ更新」をクリックする
STEP 3 更新後、管理画面を再読み込みしてエラーが消えたことを確認する

プラグイン一覧に更新通知が表示されない場合は、WooCommerce公式マーケットプレイスまたはCodeCanyonから最新版を手動でダウンロードし、FTP経由で上書きする方法もある。いずれの場合も、更新前に必ずサイト全体のバックアップを取得しておく。

バージョン4.4.4では、開発者がadmin_enqueue_scripts内に適切な画面チェックを実装し、WooCommerceの商品編集画面でのみ依存スクリプトを読み込むように修正された。そのため、他のプラグインの設定画面や投稿一覧などで無用な警告が出ることはなくなる。

すぐにアップデートできない場合の一時しのぎ

すぐにアップデートできない場合の一時しのぎ

プロジェクトの都合ですぐにプラグインを更新できない場合、応急処置としてQuery Monitorを一時的に無効化するか、プラグインファイルを手動で編集する方法がある。後者は更新時に上書きされてしまうため、あくまで次のアップデートまでのつなぎと考えてほしい。

コードを直接修正する開発者向け手順

WPC Linked Variationのプラグインフォルダ内にある wpc-linked-variation.php を開き、admin_enqueue_scripts にフックしている関数を以下のように変更する。現在の管理画面オブジェクトを取得し、投稿タイプが product の場合だけスクリプトを読み込む条件を追加する。

// 修正前(問題のあるコード)
add_action('admin_enqueue_scripts', 'wpclv_enqueue_scripts');
function wpclv_enqueue_scripts() {
    wp_enqueue_script('wpclv-backend', plugins_url('assets/js/backend.js', __FILE__), array('wc-enhanced-select', 'selectWoo'), WPC_Linked_Variation::VERSION, true);
}

// 修正後(画面チェックを追加)
add_action('admin_enqueue_scripts', 'wpclv_enqueue_scripts_fixed');
function wpclv_enqueue_scripts_fixed($hook) {
    $screen = get_current_screen();
    if ($screen && $screen->post_type === 'product') {
        wp_enqueue_script('wpclv-backend', plugins_url('assets/js/backend.js', __FILE__), array('wc-enhanced-select', 'selectWoo'), WPC_Linked_Variation::VERSION, true);
    }
}

この修正により、商品の編集・新規追加画面でのみスクリプトが読み込まれ、それ以外の管理画面ではエラーが発生しなくなる。修正後は管理画面をリロードして警告が消えることを確認する。本体のアップデートが可能になった時点で、必ず公式の最新版に差し替えることを推奨する。

よくある質問

このエラーはサイトのフロントエンドに影響しますか

影響しない。あくまで管理画面内でQuery MonitorやWordPressのデバッグ表示が警告を出すだけであり、来訪者が見る商品ページやチェックアウト画面の動作は変わらない。

プラグインを更新する以外の簡単な対処法はありますか

Query Monitorプラグインを無効化すればエラー表示自体は消えるが、あくまで表示上の回避に過ぎない。管理画面のパフォーマンスや他のスクリプト競合のリスクが残るため、プラグイン本体の更新が確実な解決策になる。

ほかのプラグインでも同様の「正しく呼び出されていません」エラーが出ます

多くのプラグインが管理画面用のスクリプトを読み込む際、WooCommerceや他のプラグインが提供するライブラリを依存関係に指定することがある。読み込むページを限定していない場合、同様の依存エラーが発生する。該当プラグインの開発者に報告するか、バージョンアップ情報を確認するのが近道だ。

バージョン4.4.4に更新してもまだエラーが消えない場合は

まずブラウザキャッシュとWordPressのキャッシュ(サーバーキャッシュやプラグインキャッシュ)をすべてクリアする。それでも消えなければ、別のプラグインが同様の問題を起こしている可能性があるため、すべてのプラグインを一時停止し、一つずつ有効化して原因を特定する。WooCommerce本体も常に最新版に保つ。

この記事のポイント

  • WPC Linked Variation 4.4.3以前に起因する管理画面のスクリプト依存エラー
  • プラグインを4.4.4以降にアップデートすれば完全に解消する
  • エラーはフロントエンドに影響せず、管理画面の表示だけの問題
  • 応急処置としてQuery Monitor無効化やコード修正も可能だが、公式更新が最も安全
  • 他プラグインでも同様の警告が起きる場合、画面チェックの有無を疑う
埋め込みチャットでNS_ERROR_DOM_COEP_FAILEDエラーが出た時の直し方

埋め込みチャットでNS_ERROR_DOM_COEP_FAILEDエラーが出た時の直し方

サイトに埋め込んだ Teams やその他のチャットウィジェットをクリックした時に NS_ERROR_DOM_COEP_FAILED と表示されて開けない場合、サーバーが返している COEP(Cross-Origin Embedder Policy)ヘッダーが原因だ。htaccess で Cross-Origin-Embedder-Policy を credentialless に変更するか、不要なヘッダーであれば削除することで解決する。

NS_ERROR_DOM_COEP_FAILEDとは何か

NS_ERROR_DOM_COEP_FAILEDとは何か

COEP は「Cross-Origin Embedder Policy」の略で、ページが他オリジン(別ドメイン)のリソースを読み込む際のセキュリティルールを定める HTTP レスポンスヘッダーだ。このヘッダーが require-corp に設定されていると、埋め込む側のリソースすべてに CORP(Cross-Origin Resource Policy)ヘッダーが付与されていることをブラウザが要求する。

Teams のチャットウィジェットをはじめ、多くのサードパーティ製ウィジェットは自社の配信サーバーから JavaScript や画像を読み込むが、それらのリソースに CORP ヘッダーが付与されていないことが多い。結果としてブラウザが読み込みをブロックし、NS_ERROR_DOM_COEP_FAILED というエラーをコンソールに出力する。

このエラーは Firefox や Chrome などのモダンブラウザで発生し、ウィジェットのボタンは表示されるがクリックしてもチャット画面が開かない、または読み込み中のまま固まるといった症状が出る。

COEPエラーが発生する仕組み
自サイトのサーバー
COEPヘッダーを require-corp で返している
Teams ウィジェット(他オリジン)
配信する JS や画像に CORP ヘッダーが付いていない
ブラウザがブロック
NS_ERROR_DOM_COEP_FAILED を出力しウィジェットが開かない
エラーの流れ  外部リソース

この図のとおり、自サイトのサーバー設定と外部ウィジェットの配信仕様が噛み合わず、ブラウザが安全側に倒して読み込みを拒否するのが根本的な原因だ。

自サイトにCOEPヘッダーが設定されているか確認する手順

自サイトにCOEPヘッダーが設定されているか確認する手順

まずは自サイトが実際に COEP ヘッダーを返しているかどうかを確認する。ブラウザの開発者ツールを使えば数分で特定できる。

Chrome や Firefox の開発者ツールでレスポンスヘッダーを確認する

サイトの任意のページを開き、F12 キーで開発者ツールを起動する。NetWork タブを開いてページを再読み込みし、先頭のドキュメントリクエスト(多くの場合はページURLそのもの)をクリックする。Response Headers セクションに Cross-Origin-Embedder-Policy という項目があれば、その値が現在の設定だ。

値が require-corp になっている場合、厳格な制限がかかっている状態で、これがエラーの直接原因になる。値が credentialless であればクロスオリジンの埋め込みは許可されているため、別の要因を探す必要がある。ヘッダー自体が存在しない場合は、COEP 以外の原因(CORS 設定やウィジェット側のスクリプトエラーなど)を疑う。

セキュリティプラグインやCDNが自動付与しているケース

WordPress サイトの場合、セキュリティ系プラグインが HTTP レスポンスヘッダーを自動で追加していることがある。また Cloudflare などの CDN サービスを経由していると、CDN 側のセキュリティ設定で COEP ヘッダーが付与されるケースもある。

該当しそうなプラグインを一つずつ無効化してヘッダーの変化を確認するか、CDN の管理画面で「ヘッダー設定」や「セキュリティヘッダー」といった項目をチェックすると原因を絞り込める。

htaccessでCOEPヘッダーを修正してエラーを解決する

htaccessでCOEPヘッダーを修正してエラーを解決する

原因が COEP ヘッダーの require-corp 設定にあると特定できたら、htaccess ファイルを編集して修正する。Apache サーバーを使っている国内レンタルサーバーの大半は htaccess による上書きが可能だ。

STEP 1 FTP またはサーバーのファイルマネージャーでサイトのルートディレクトリにアクセスする
STEP 2 .htaccess ファイルをダウンロードしバックアップを取る(必須)
STEP 3 COEP ヘッダーを credentialless に設定するコードを追記する
STEP 4 ファイルをアップロードしブラウザキャッシュをクリアして動作確認する

上記 STEP 3 で追記するコードは以下のとおりだ。htaccess の末尾にこのブロックを追加する。

<IfModule mod_headers.c>
Header set Cross-Origin-Embedder-Policy "credentialless"
</IfModule>

この設定により、COEP ヘッダーが credentialless モードに切り替わる。credentialless はクロスオリジンのリソース読み込みを許可しつつ、認証情報(Cookie や HTTP 認証)を送信しないモードだ。Teams のチャットウィジェットは認証に Cookie を使わず独自のトークンで認証するため、credentialless モードでも問題なく動作する。

COEPヘッダーを完全に削除する方法

セキュリティ上の要件が特にないサイトであれば、COEP ヘッダー自体を削除する選択肢もある。以下のコードを htaccess に追記すればヘッダーが除去される。

<IfModule mod_headers.c>
Header unset Cross-Origin-Embedder-Policy
</IfModule>

どちらの方法を選ぶかはサイトのセキュリティポリシー次第だ。COEP ヘッダーが元々セキュリティプラグインや CDN の自動設定で付与されていたのであれば、credentialless への変更が無難だ。手動で require-corp を指定していた場合は、その意図を再確認した上で削除または変更を判断する。

htaccess編集後に変更が反映されない場合の確認ポイント

ファイルをアップロードしてもヘッダーが変わらない場合、mod_headers モジュールがサーバーで有効になっていない可能性がある。また、CDN を経由しているサイトでは CDN のキャッシュをパージしないと変更がすぐに反映されない。WordPress のキャッシュプラグインを使っている場合も、プラグインの設定画面からキャッシュを全削除する。

変更後は必ず開発者ツールの NetWork タブでレスポンスヘッダーを再確認し、Cross-Origin-Embedder-Policy の値が credentialless に変わっているか、ヘッダー自体が消えているかを検証する。

htaccessが使えないサーバー環境での対処法

htaccessが使えないサーバー環境での対処法

Nginx を使っている VPS やクラウド環境では htaccess が使えない。また一部の共用サーバーでは mod_headers が無効化されている場合もある。そうしたケースでの対処法をまとめる。

Nginxの場合

Nginx の設定ファイル(nginx.conf またはサイト単位の conf ファイル)の server ブロック内に以下の行を追加する。

add_header Cross-Origin-Embedder-Policy "credentialless";

記述後は nginx -t で設定ファイルの文法チェックを行い、問題がなければ nginx -s reload で設定を再読み込みする。sudo 権限が必要な操作のため、レンタルサーバーではサポートに依頼する必要がある。

CDNやWAFでヘッダーを操作する

Cloudflare を使っている場合、ダッシュボードの「ルール」から「HTTP レスポンスヘッダーを変更」ルールを作成し、Cross-Origin-Embedder-Policy を credentialless に上書きできる。サーバー側の設定を一切触らずに済むため、htaccess 編集に不安がある場合の現実的な代替手段になる。

PHPでヘッダーを直接出力する

WordPress のテーマの functions.php に以下のコードを追加する方法もある。テーマ更新時に消えないよう、必ず子テーマを使う。

function my_set_coep_header() {
    header('Cross-Origin-Embedder-Policy: credentialless');
}
add_action('send_headers', 'my_set_coep_header');

この方法はサーバー設定に依存せず、WordPress の仕組みだけでヘッダーを制御できる。ただし、テーマの functions.php を編集するため、誤った記述があるとサイトが表示できなくなるリスクを伴う。編集前に必ず functions.php のバックアップを取る。

よくある質問

COEPエラーは特定のブラウザだけに出るのか

Firefox と Chrome 系ブラウザ(Chrome、Edge、Brave など)で発生する。Safari は COEP への対応が遅れていたが、Safari 17.2 以降はサポートしている。ブラウザによってエラーメッセージの文言は異なるが、根本原因は同じ COEP ヘッダーだ。

WordPressのセキュリティプラグインが原因になることはあるか

ある。HTTP セキュリティヘッダーを自動付与する機能を持つプラグイン(セキュリティ全般を扱うプラグインやヘッダー専用プラグイン)が、COEP を含むヘッダーを一括で設定しているケースは多い。プラグインの設定画面で「セキュリティヘッダー」や「HTTP ヘッダー」項目を探し、COEP の値を変更または無効化する。

credentiallessとrequire-corpの違いは何か

require-corp は埋め込み先の全リソースに CORP ヘッダーを必須とする厳格モードだ。一方 credentialless は CORP ヘッダーなしでもクロスオリジン読み込みを許可するが、認証情報(Cookie など)は送信しない。Teams チャットのような独自認証を使うウィジェットでは credentialless で十分動作する。

埋め込みウィジェット側の設定で回避できるか

原則として難しい。COEP エラーは「読み込む側(自サイト)」の制限によって発生するため、ウィジェット提供元(Teams など)の設定で回避する手段はない。ウィジェット提供元が自社の全配信リソースに CORP ヘッダーを付与すれば解決するが、それを個別の利用者が依頼して実現するのは現実的ではない。

htaccess編集に自信がない場合はどうすればよいか

サーバーの管理画面からファイルマネージャーで操作する場合は、編集前に必ず htaccess をコピーしてローカルに保存する。ミスでサイトが表示できなくなったら、そのバックアップをアップロードし直せば元に戻る。どうしても不安な場合は、CDN のヘッダー変更機能や PHP の functions.php で対応する方法を検討する。

この記事のポイント

  • NS_ERROR_DOM_COEP_FAILED はサーバーの COEP ヘッダーが require-corp の時に発生する
  • Teams など多くの外部ウィジェットは CORP ヘッダーを返さないためブロックされる
  • htaccess で COEP を credentialless に変更するかヘッダーを削除すれば解決する
  • Nginx 環境や CDN 経由の場合は別の設定手順が必要になる
  • 修正後は必ず開発者ツールでレスポンスヘッダーが変わったか確認する