第4回:PHPだけでは解決できない「動かない」の深層。Reactエラーとヘッドレス時代のデバッグ
WordPressのトラブル対応は、長らくPHP中心のデバッグで成立してきました 。サーバーのエラーログを確認し、致命的なエラー(Fatal Error)を修正して再アクセスする。しかし、ブロックエディタ以降のWordPressでは、このアプローチだけでは説明できない不具合が確実に増えています 。
- 保存ボタンを押しても反応しない 。
- 「更新に失敗しました」とだけ表示される 。
- 管理画面だけが壊れて、フロントエンド(公開画面)は正常に表示される 。
PHPのログには何も出ていないのに、操作が成立しない。これは例外ではなく、現在のWordPressの構造上、必然的に起きる問題です 。本稿では、PHPの先にある「実行層」のデバッグ術を詳しく解説します。
WordPressはいつから「PHPのCMS」ではなくなったのか
現在のWordPress管理画面、特にブロックエディタ(Gutenberg)は、ブラウザ上のアプリケーションとして動作しています。かつてのようにPHPがHTMLを組み立てて出力するのではなく、現在のWordPress管理画面、特にブロックエディタ(Gutenberg)は、
- React(UIと状態管理)
- JavaScript(操作ロジック)
- REST API(データ通信)
によって構成されたブラウザ上のアプリケーション です。
ここで重要なのは、役割分担です。
| 層 | 役割 | 担当 |
| UI・操作 | ユーザーのクリックや入力の受付 | React / JavaScript |
| 通信 | データのやり取り(中継) | REST API |
| 保存処理 | データベースへの書き込み | PHP |
| 表示更新 | 保存結果を画面に反映させる | React |
PHPは今や「最後に保存する人」です。
画面が壊れている=PHPの問題とは限らない。
この前提を受け入れない限り、
第3回で扱ったINP(体感速度)も、
今回のJSエラーも、理解は分断されたままです。
「更新に失敗しました」の裏側で起きていること
ブロックエディタで保存するとき、内部では次の流れが起きています。
- Reactが編集状態を管理
- REST APIへJSON形式でデータを送信
- PHPが受け取ったデータをDBに保存
- JSONで処理結果(成功・失敗)を返却
- Reactがその返却データを解釈し、画面を更新

「更新に失敗しました」というメッセージは、
このどこかで契約違反が起きた
という最終結果の表示にすぎません。
REST APIとは、
- HTTP通信を使い
- JSON形式で
- クライアントとサーバーがデータをやり取りする
仕組みです。
JSONとは、
テキストベースのデータフォーマットです。軽量で読みやすいのが特徴ですが、1文字でも余計な出力が混じると解析(パース)できず壊れてしまうという繊細な性質を持っています 。
ここでの最重要ポイントはこれです。
JSONは1文字でも余計な出力が混じると壊れる
PHP側で以下のような出力が混入すると、PHPの処理自体は成功していても、ReactがJSONを解釈できず「保存失敗」となります 。
- echo / var_dump:
デバッグ用の出力がそのまま残っている 。 - Notice / Warning:
致命的ではないが、PHPが出力してしまう警告文 。 - BOM(バイトオーダーマーク):
ファイルの先頭に隠れている不可視のコード 。 - HTMLタグ / 空白:
意図しない改行やスペース 。
ブラウザのDevTools(開発者ツール)の「Network」タブを開き、REST APIのレスポンスの「生(Raw)データ」を確認してください。先頭や末尾に、JSON以外の文字が混じっていないかをチェックするのが最短の解決策です 。

Minified React Error と SourceMap の活用

DevToolsのコンソールで「Minified React error #130」のような番号のエラーが出るのは、Reactが本番用に最適化(Minify)されているためです。
Minify(最適化、圧縮):
ファイルサイズ削減と実行速度向上のため、コード内のスペースを詰め、変数名を短くし、エラーメッセージを番号に置き換える処理です 。
ReactとMinifyの関係
Reactは開発環境では、
- どのコンポーネントで
- 何が壊れたか
を詳細に表示します。
しかし本番環境では、
- ファイルサイズ削減
- 実行速度最適化
のため、
エラーメッセージを番号に置き換えます。
エラーメッセージを番号で置き換えている仕組みとは?
この仕組みをSourceMapで実現しています。具体的には、
- 圧縮後のJS
- 元の人間可読なJS
を対応付ける 地図ファイル(.map) です。
DevToolsでSourceMapが有効であれば、
- 実際の関数名
- 元の行番号
- 呼び出し元
まで遡れます。
本番と同じ構成をローカルやステージング環境で再現し、開発モードでフルメッセージを確認するのが上級者の手順です。
jQueryとReactの共存と「思想」の違い
WordPressはいまも jQuery を同梱しています。
一方、ブロックエディタは React 前提です。
問題は思想ではありません。
前提モデルの違い です。
jQueryの前提
- DOMを直接操作
$はグローバル- 状態=DOM
Reactの前提
- 状態が真実
- DOMは結果
- 直接操作すると破綻
両者が無秩序に混ざると、
$ is not defined$ is not a function- 状態とDOMが乖離する
という表示画面とデータが乖離する事故が起きます。
共存の原則
jQueryを使用する場合は、必ず以下の形式でスコープを閉じ、React側の管理領域に侵食させないことが安定稼働の条件です 。
jQuery(function($){
// jQueryはこのスコープ内だけで完結させ、グローバルを汚染しない
});JavaScript$をローカルに閉じる- React側に侵食させない
混ぜないことが最大の最適化です。
webpack / npm が絡むと「本番だけ壊れる」理由
ここから話は ビルドの世界 に移ります。
npmとは何か
npmは、
- JavaScriptライブラリの取得
- 依存関係の管理
を行うツールです。node_modules にすべてが展開されます。
webpackとは何か
webpackは、
- 複数のJS
- npm依存
を ブラウザ向けに束ねる(bundle) ツールです。
現代のJS(ESM / JSX / TS)は、そのままでは動かないことが多く、ビルドが前提になります。
なぜローカルでは動くのか
- node_modules が存在
- 開発モード
- SourceMap 有効
- 多少の依存欠損を許容
なぜ本番で壊れるのか
- ビルド成果物のみ配置
- node_modules 不在
- 読み込み順は WordPress に依存
ここで WordPress特有の罠 が発生します。
WordPressでは「依存解決の責任者」が違う
WordPressには wp_enqueue_script という公式の読み込み機構があり、下記を担っています 。
- 読み込み順を保証
- 依存関係を解決
- 二重ロードを防止
webpackでReactをbundleし、WordPress側でも wp-element(React)を読み込むと、
- React二重ロード
- グローバル状態破綻
- ブロックエディタが沈黙
Reactを二重に読み込んだ瞬間、エディタは静かに死にます🪦
それでは正しい設計原則は?
- React / wp-element は WordPressに任せる
- webpackでは externals 指定
- 依存関係は wp_enqueue_script で宣言
ヘッドレスWordPressでは問題はどこに移るか
- 表示(フロント)を分離
- WordPressをデータAPIとして利用
する構成です。
この瞬間、問題は PHP から ブラウザの制約 に移ります。
CORSと認証は「別物」だが同時に壊れる
CORSとは何か
CORS(Cross-Origin Resource Sharing)とは、異なるドメイン間での通信を、ブラウザがセキュリティのために制限する仕組みです。
サーバー側が許可を出していても、ブラウザ側で通信を破棄することがあります 。
認証(JWT、App Password等)とCORSは全くの別物です。
認証方式ごとの違い
| 方式 | 特徴 |
|---|---|
| JWT | Authorizationヘッダ必須 / CORS必須 |
| App Password | HTTPS必須 / 管理用途向き |
| Cookie | SameSite制約に注意 |
最重要ポイント
認証が正しくてもCORSが通らなければ失敗
CORSが通っても認証が誤っていれば失敗
これは AND条件 です。
本番JSトラブル時のチェックリスト
不具合が発生した際は、以下の順に確認してください 。
- Networkタブ:
REST APIのJSONに余分な出力が混じっていないか 。 - Consoleタブ:
Reactのエラー(Minified Error等)が出ていないか 。 - 環境再現:
SourceMapが使えるローカル等の開発環境で再現するか 。 - 二重ロード:
Reactが複数回読み込まれていないか 。 - 依存関係:
wp_enqueue_scriptの依存定義が正しいか 。 - CORS/認証:
ブラウザが通信を遮断していないか同時に確認 。
上級者Q&A:管理画面・ブロックエディタのJSトラブル実践編
Q1.PHPエラーもREST APIエラーも出ていないのに、保存だけが失敗します。どこを見るべきですか?
最初に確認すべきは、Networkタブに表示されるREST APIレスポンスの「生JSON」です。
WordPress REST APIでは、
- PHPの処理が致命的エラーを起こしていない場合
- warning / notice / 余分な出力が混入しても
HTTPステータスが 200 OK のまま返るケースがあります。
この場合、
- PHPは成功している
- しかしブラウザ側(React)がJSONを解釈できず失敗する
という状態になります。
チェックポイントは以下です。
- レスポンス先頭・末尾に
- notice
- warning
- HTMLタグ
- 空白
が混入していないか?
- Consoleに 「
Unexpected token <」などが出ていないか?
これは
「PHPは正常、JSだけが失敗する」典型例です。
Q2.Minified React error が出ていますが、番号しか表示されません。本番環境でどう対処しますか?
原則として、本番環境での直接解析は行いません(行えません)。
理由は次の通りです。
- 本番では SourceMap が無効・非公開なことが多い
- minified bundle は人間が読む前提で作られていない
React公式・WordPress公式の実務でも、
再現環境(ローカル/ステージング)での解析が推奨されています。
Gutenberg ブロック開発
→ https://developer.wordpress.org/block-editor/getting-started/
(“開発環境を整える” という公式ドキュメント)
開発環境セットアップ
→ https://react.dev/learn/installation
(ローカル開発サーバーで動作確認するのが前提)
正しい手順は、
- 本番と同じ構成をローカルまたはステージングで再現
- 開発モードで同じ操作を実行
- フルメッセージのReactエラーを確認
※例外として、SourceMapが公開されている場合のみ本番解析が可能です。
Q3.jQueryとReactが混在している既存テーマを、全面的に書き換えず安定させる方法はありますか?
あります。ただし条件付きです。
重要なのは 共存ではなく「責務の分離」 です。
- jQuery
- 管理画面外
- 単発UI操作
- DOM直接操作が前提
- React
- ブロックエディタ内部
- 状態管理が前提
jQueryは必ず次の形でスコープを閉じます。
jQuery(function($){
// jQueryはこの中だけで完結させる
});JavaScriptReactの管理下に
DOM直接操作を侵入させないこと が安定条件です。
これは WordPressコア自身が採用している設計とも一致します。
Q4.webpackでビルドしたJSが、本番のブロックエディタだけで壊れます。よくある原因は何ですか?
実務上、非常に多い原因の一つが React(wp-element)の二重ロードです。
原因としてよく見られるのは、
- webpackでReactをbundleしている
- WordPress側でも
wp-element(React)をenqueueしている
という 責務の衝突 です。
この状態では、
- Reactのグローバル状態が分断され
- ブロックエディタが正常に初期化できなくなります
対策は明確です。
- webpackではReactを
externals指定 - 依存関係の解決は
wp_enqueue_scriptに任せる
依存解決はWordPress側に一元化する
これが最も安全な設計です。
Q5.ヘッドレスWordPress構成で、APIは正常なのにフロントエンドだけが失敗します。何を疑うべきですか?
まず CORS → 認証の順で確認します。
重要なのは、CORSは
- サーバーではなく
- ブラウザ側で通信を遮断する仕組み
だという点です。
特にJWT認証では、
- Authorization ヘッダ
- preflight(OPTIONS)
Access-Control-Allow-Headers
が正しく設定されていないと、
認証以前に通信が破棄されます。
この場合、
- サーバー側ログに何も残らない
- API自体は正常に見える
という状態になります。
Q6.JSエラーを放置すると、実務上いちばん危険なことは何ですか?
壊れた状態のデータがDBに保存される可能性があることです。
ブロックエディタでは、
- ブロック属性
- post meta
が JSON構造として保存されます。
JS側で、
- 状態欠損
- 属性不整合
が起きた状態で保存されると、
壊れたデータがそのまま永続化されることがあります。
常にDBが壊れるわけではありませんが、
条件が揃うと 後からJSを直しても戻らない事故 になります。
このため、
JSエラーは
「画面の問題」ではなく
「DB事故の入口」
として扱う必要があります。
まとめ
最も警戒すべきは、「壊れた状態のデータがDBに保存されるリスク」にあります 。
ブロックエディタでは、各ブロックの属性や設定がJSON構造として保存されます 。JS側で不整合が起きた状態で保存が実行されると、不完全なデータがそのままDBに永続化されてしまいます 。
これは単なる「表示の不具合」ではありません。
ハッキングやマルウェアによる改ざんと、JSエラーによるデータ欠損は、DBから見れば同じ「意図しないデータの書き換え」です。
- ハッキング/改ざん:
悪意あるスクリプトがDB内のJSON構造を書き換え、バックドアを仕込む。 - JSエラー:
不具合のあるスクリプトがDB内のJSON構造を破壊し、サイトを機能不全にする。
どちらも「後からプログラムを直しても、壊れたデータは元に戻らない」という致命的な事故に直結します 。
JSエラーは「画面の問題」ではなく、「DB事故、あるいはセキュリティ侵害の入口」として扱うべき重大なサインなのです 。
ここまで把握して初めて、近年のWordPressトラブルを根本から解決できる上級者となります 。
「戻れない事故」を扱います。
マルウェア感染によるデータ改ざん、DB移転時のシリアライズ破壊など、JSの失敗や外部攻撃が「データベースへ永続化される瞬間」とその救出策について解説します 。

