WordPress・CMS設計

Gutenbergカスタムブロック開発におけるReactとPHPの使い分け

Gutenbergで自作ブロックを開発していると、ある日突然、エディター上に「このブロックには予期しない変更が加えられています」といったバリデーションエラーが表示されることがあります。保存したはずのHTMLと、現在のブロックが生成しようとしているHTMLが一致しなくなったときに起きる問題です。…

Gutenbergカスタムブロック開発におけるReactとPHPの使い分け

一方で、PHPを使った動的ブロックに切り替えれば、すべての問題が解決するわけではありません。記事一覧や現在の年のように、表示時点で内容を生成したい場合には動的レンダリングが向いていますが、編集画面での入力体験や、保存されるコンテンツの扱い方まで考えると、静的ブロックのほうが自然なケースもあります。

つまり、Gutenbergの自作ブロックで考えるべきなのは、ReactとPHPのどちらが優れているかではありません。どのタイミングでHTMLを作るのか、データベースに何を保存するのか、将来どのように表示内容が変わるのかという、ブロックの仕組みそのものです。

この記事では、GutenbergにおけるReactとPHPの役割を整理しながら、静的ブロックと動的ブロックの違い、バリデーションエラーが発生する理由、そして要件に合わせた選び方を順番に見ていきます。

Gutenbergの自作ブロックは「いつHTMLを作るか」で考える

Gutenbergのブロック開発では、エディター画面での操作と、サイト訪問者が見る画面の表示を分けて考える必要があります。

ブロックを編集しているときは、入力欄や画像選択、設定パネルなどのエディター用の画面が必要です。ここでは主にedit.jsが使われ、ブロックの編集UIを定義します。

その一方で、記事が保存されたあと、訪問者がフロントエンドで見るHTMLをどのように作るかには、次の2つの方式があります。

  • 保存時にHTMLを作り、投稿コンテンツの一部として保存する静的レンダリング
  • ページを表示するタイミングでPHPがHTMLを生成する動的レンダリング

静的ブロックでは、save.jsがフロントエンド用のHTMLを生成します。ブロックの属性として保存された内容をもとに、見出しやカード、ボタンなどのマークアップを作り、それを投稿本文の中に保存しておく仕組みです。

動的ブロックでは、save.jsで完成したHTMLを保存する代わりに、render.phpまたはrender_callbackを使って、ページ表示時にHTMLを生成します。データベースから最新の情報を取得したり、現在の日時に応じて表示を変えたりする場合はこちらが適しています。

ここで混同しやすいのが、ReactとPHPを完全に対立する技術として考えてしまうことです。Reactは主にGutenbergエディター上の操作画面を構築するために使われ、PHPはサーバー側で表示内容を組み立てるために使われます。静的ブロックでReactを使い、動的ブロックでPHPを使うことは多いものの、実際には両者を組み合わせる設計も一般的です。

ReactかPHPかを先に決めるのではなく、ブロックのHTMLを保存時に確定させるのか、表示時に生成するのかを先に決めてみましょう。

静的ブロックの仕組みとReactの役割

edit.jsとsave.jsは別々の責任を持つ

静的ブロックでは、少なくとも2つの表示を分けて実装します。

edit.jsは、管理画面のブロックエディターで表示するUIです。ユーザーがテキストを入力したり、画像を選択したり、ブロックの設定を変更したりするための画面を定義します。

save.jsは、投稿を保存したあとにフロントエンドへ出力するHTMLを定義します。編集画面で使っているボタンや入力欄をそのまま表示するのではなく、訪問者向けのマークアップとして整理する役割があります。

たとえば、告知ボックスを作る場合を考えてみましょう。編集画面では、本文を入力するための編集用コンポーネントや、色を選択する設定UIが必要になります。しかし、フロントエンドでは、入力欄ではなく、確定した見出しと本文を含む告知ボックスとして表示しなければなりません。

この2つのHTML構造が異なること自体は問題ではありません。問題になるのは、保存済みのブロックHTMLと、現在のsave.jsが生成するHTMLが、ブロックの検証時に一致しない場合です。

Reactを使う理由は「画面を部品として管理できる」こと

Gutenbergのブロック開発では、Reactのコンポーネント構造を使って編集画面を組み立てます。ここでの利点は、単に新しい技術を使えることではありません。

入力欄、ボタン、画像選択、インライン装飾、サイドバーの設定などを部品として整理できるため、ブロックの状態とUIの関係を追いやすくなります。特に複数の属性を持つブロックでは、編集操作によってどの属性が変わり、どのHTMLが保存されるのかを管理しやすくなります。

また、Gutenberg自体がReactを前提としたエディターであるため、標準のコンポーネントやデータ管理の仕組みと組み合わせやすい点もあります。WordPressの管理画面に馴染む操作UIを作りたい場合、Reactを避けて独自の仕組みだけで構築するより、既存のブロック開発の流れに沿ったほうが再現性を持たせやすいでしょう。

ただし、Reactを使う範囲は主にエディターUIです。フロントエンドの表示までReactで構築しなければならない、という意味ではありません。静的ブロックであれば、Reactで編集画面を作り、save.jsで保存用のHTMLを出力するという構成が基本になります。

静的ブロックが扱いやすいコンテンツ

静的ブロックは、保存した時点で内容が確定するコンテンツに向いています。

たとえば、次のようなブロックです。

  • 見出しと本文を組み合わせた告知ボックス
  • 画像、キャプション、説明文を含むメディアブロック
  • ボタンとリンク先を設定できるCTAブロック
  • FAQの質問と回答を入力して表示するブロック
  • 装飾付きの引用や、固定的なプロフィールカード
  • 商品やサービスの説明を編集者が直接入力するブロック

これらは、投稿を保存した時点の内容を、そのまま訪問者に表示できれば成立します。アクセスのたびにデータベースから最新情報を取り直す必要がないため、仕組みが比較的理解しやすく、出力されたHTMLを確認しやすいのも特徴です。

もちろん、静的だからといって必ず高速になる、あるいは動的だから必ず遅くなる、と単純に決めつけることはできません。キャッシュやクエリ、サーバー構成なども関係します。ただ、表示のたびに処理を実行する必要がないという点では、静的ブロックは構成を小さく保ちやすい方式です。

静的ブロックで起きるバリデーションエラーの仕組み

保存済みHTMLと現在の出力がずれるとエラーになる

Gutenbergの静的ブロックでは、投稿本文にブロックのマークアップが保存されます。再び投稿を開いたとき、WordPressは保存されているHTMLと、現在のブロック定義から生成されるHTMLを比較します。

ここで両者が一致しないと、バリデーションエラーが発生します。

原因は、単純なHTMLの変更だけとは限りません。次のような変更でも問題になることがあります。

  • save.jsで出力するタグの構造を変更した
  • 要素に付けていたクラス名を変更した
  • 属性値の保存形式を変更した
  • 空の属性を出力するかどうかが変わった
  • リッチテキストのマークアップが変わった
  • ブロックの属性定義と保存されている内容が合わなくなった
  • WordPressや関連パッケージの更新で出力結果が変わった

たとえば、以前はp要素の中に文章を保存していたのに、後からdiv要素へ変更した場合、見た目がほぼ同じでも保存済みHTMLとの構造は異なります。ブロックから見れば、別のマークアップです。

この問題は、開発中にHTMLを頻繁に変更する段階で特に起こりやすくなります。エディター画面では正しく表示されていても、過去に保存した記事を開いた瞬間にエラーが出るため、変更の影響範囲を見落としやすいのです。

バリデーションエラーを「無視する」前に確認したいこと

バリデーションエラーが表示されたとき、編集画面からブロックを修復したり、HTMLへ変換したりすることはできます。しかし、それは問題の原因を解決したとは限りません。

まず確認したいのは、次の3点です。

1. 変更前と変更後で、保存HTMLの構造がどこまで変わったか

2. 属性名や属性の型、初期値に変更がないか

3. すでに公開済みの記事へどの程度影響するか

特に、公開済みの投稿に多数のブロックが配置されている場合、save.jsの変更は過去記事全体に波及します。新規投稿だけで検証していると、既存コンテンツに対する影響を把握できません。

見た目を改善するためにクラス名を変更しただけでも、保存マークアップが変わることがあります。このような場合は、CSSだけで対応できないか、あるいはブロックのバージョン管理や移行処理を用意できないかを検討してみましょう。

静的ブロックでは、保存されるHTMLがコンテンツの一部になります。そのため、save.jsは単なる表示テンプレートではなく、過去のコンテンツとの互換性にも関わる重要なファイルです。

PHPによる動的ブロックが適している場面

表示時点で最新情報を取得したい場合

動的ブロックは、投稿を保存した時点ではなく、ページを表示する時点でHTMLを生成します。そのため、保存後に変化するデータを扱う場合に向いています。

代表的なのが、最新記事一覧です。投稿を作成した時点で記事一覧を保存してしまうと、その後に公開された記事を自動的に反映できません。表示時にPHPで投稿情報を取得すれば、常に現在の条件に合った記事一覧を出力できます。

同じように、次のようなコンテンツも動的ブロックと相性がよいでしょう。

  • 最新の投稿や特定カテゴリーの記事一覧
  • 実行時点の現在年や更新日時
  • カスタム投稿タイプの一覧
  • データベースに保存された店舗情報やイベント情報
  • 管理画面で変更した設定値を全ページに反映する表示
  • 関連記事や人気記事など、表示時に条件が変わる情報

こうしたデータを静的ブロックで保存すると、情報を更新するたびに各投稿を書き換える必要が生じます。記事数が少ないうちは運用で対応できても、ページが増えるほど更新漏れのリスクが高くなります。

render.phpとrender_callbackの役割

動的ブロックでは、表示用の処理をPHPに記述します。方法としては、render.phpを使う構成と、PHPのコールバック関数を登録する構成があります。

render.phpを使う場合は、ブロックの属性を受け取り、その値をもとにHTMLを出力します。表示用テンプレートと処理を分離しやすいため、マークアップを確認しながら実装したいケースに向いています。

一方、render_callbackを使う場合は、ブロック登録時にPHPの関数を指定し、その関数内でHTMLを生成します。条件分岐やデータ取得を細かく制御したい場合には柔軟ですが、処理が大きくなると登録処理と表示処理が混ざりやすくなります。

どちらを使う場合でも、重要なのは、編集画面の定義とフロントエンド表示の責任を分けることです。編集画面はReactで作り、訪問者向けの表示はPHPで生成するという構成にすれば、それぞれの得意分野を活かせます。

動的ブロックではsave.jsをどう扱うか

動的ブロックでは、フロントエンドの完成HTMLをsave.jsで保存しません。一般的には、ブロックのコメントと属性情報を保存し、実際の表示HTMLはPHP側で生成します。

この構成にすると、保存済みHTMLと現在のPHP出力を比較する静的ブロック特有のバリデーション問題を避けやすくなります。表示テンプレートを変更しても、保存されている属性情報が維持されていれば、過去記事にも変更後の表示を適用できます。

ただし、動的ブロックにも注意点があります。PHP側の処理が変われば、過去の記事の表示も一斉に変わります。これは便利な反面、意図しないタイミングでサイト全体の見た目が変わる可能性があるということです。

また、表示のたびにデータ取得や処理を行うため、クエリの内容やキャッシュ戦略が重要になります。最新記事一覧を表示する処理であれば、取得件数や条件を適切に絞り、必要以上に重い処理を入れないように設計してみましょう。

ReactとPHPの違いを実装方式で比較する

Gutenbergの自作ブロックでReactとPHPを使い分けるときは、技術名だけで比較するよりも、保存と表示のプロセスを並べてみると理解しやすくなります。

比較項目Reactによる静的ブロックPHPによる動的ブロック
編集画面edit.jsでUIを構築するedit.jsでUIを構築することが多い
フロントエンド表示save.jsでHTMLを保存するrender.phpまたはrender_callbackで生成する
表示内容の確定時期投稿保存時ページ表示時
最新データの反映投稿を更新しない限り反映されない表示時に取得すれば反映できる
バリデーション保存HTMLと現在の出力がずれると問題になりやすい静的HTMLの差分による問題を避けやすい
表示の制御保存済みのマークアップを中心に管理するPHP側で条件分岐やデータ取得を行う
適した用途固定的な本文、告知、カード、装飾記事一覧、現在日時、動的なデータ表示
保守時の注意点過去記事とのHTML互換性PHP処理、クエリ、キャッシュへの影響

ここで見ておきたいのは、PHPによる動的ブロックでも、編集画面までPHPだけで作るとは限らないことです。GutenbergのエディターUIはReactベースの仕組みと相性がよいため、edit.jsを使って入力体験を設計し、表示処理だけPHPに任せる構成が現実的です。

反対に、Reactを使った静的ブロックでも、すべてのデータをReactだけで取得しなければならないわけではありません。WordPressのブロックとして保存すべき情報と、表示時に取得すべき情報を分けることが、設計の中心になります。

「Reactなし」でGutenbergのブロックを作れるのか

Reactを完全に避けることと、フロントエンドをReactにしないことは違う

WordPressのカスタムブロック開発で、Reactなしの方法を探している方は少なくありません。既存のPHPテーマやプラグインに少しだけ機能を追加したい場合、JavaScriptのビルド環境まで導入することに負担を感じるのは自然なことです。

ただし、ここでは「Reactを使わない」という言葉を分けて考える必要があります。

Gutenbergの編集画面で複雑なUIを作る場合、Reactベースのブロック開発環境を使うことが一般的です。一方で、フロントエンドの表示をReactで構築する必要はありません。動的ブロックとしてPHPで表示するだけなら、訪問者向けの画面にReactを読み込ませずに済みます。

また、PHP主体でブロックの表示処理を書く方法もあります。ただし、編集画面でどのような入力体験を提供するのかによって、必要なJavaScriptの量は変わります。単純な属性入力で済むブロックと、複数のインタラクションを持つブロックでは、開発コストが同じではありません。

PHP主体が向いているケース

PHP主体の構成を検討しやすいのは、次のような場合です。

  • 編集画面のUIが単純で、複雑な状態管理が必要ない
  • 表示内容をサーバー側のデータから組み立てたい
  • 既存テーマのPHPテンプレートと処理を共有したい
  • 動的な一覧や条件分岐が中心になっている
  • フロントエンドへ追加のJavaScriptを配信したくない

ただし、ここでも「PHPだけなら簡単」と考えないように注意してください。サーバー側で表示を生成する場合、属性値の扱い、出力のエスケープ、クエリの条件、権限による表示分岐など、PHP側で設計すべき要素が増えます。

Reactを使わないこと自体が目的になると、結果として独自の入力処理や複雑な管理画面を作ることになり、仕組み全体が分かりにくくなる場合があります。あなたが減らしたいのはReactそのものなのか、それともビルド環境の管理負担なのかを切り分けてみましょう。

@wordpress/create-blockで開発環境を整える

ひな形作成ツールが解決する問題

Gutenbergの自作ブロックでは、JavaScriptのソースを用意するだけでは開発を始められません。ソースコードを変換し、複数ファイルをまとめ、ブラウザーで読み込める形にビルドするプロセスが必要になります。

この環境を自分で構築しようとすると、webpackやBabelの設定、依存パッケージ、開発用と本番用のビルド方法などを一つずつ管理しなければなりません。WordPressのブロック開発そのものを学びたい段階で、ビルド設定の差分に時間を取られるのは避けたいところです。

公式のひな形作成ツールである@wordpress/create-blockを利用すると、@wordpress/scriptsに統合されたビルド環境を前提として、標準的なブロックの雛形を作成できます。webpackやBabelを最初から個別に組み立てるのではなく、WordPressのブロック開発で利用される構成に沿って始められる点が利点です。

たとえば、プロジェクトの作成時にはnpx @wordpress/create-blockを使ってブロックの雛形を生成します。このコマンドが必要なのは、単にファイルを自動作成するためだけではありません。ブロック登録に必要な設定、編集用ファイル、保存用ファイル、ビルドに必要な定義を、一定の構成で揃えるためです。

コマンドの意味を理解して使う

コマンドを実行するときは、生成されたファイルを眺めるだけで終わらせないようにしましょう。

少なくとも、次のファイルがどの役割を持つのかを確認してみてください。

  • block.json:ブロック名やスクリプト、スタイル、属性などを定義する設定
  • edit.js:エディター上の編集UIを定義するファイル
  • save.js:静的ブロックで保存するHTMLを定義するファイル
  • render.php:動的ブロックで表示時のHTMLを生成するファイル
  • index.js:ブロックの登録処理をまとめるエントリーポイント
  • package.json:開発用コマンドや依存関係を管理するファイル

すべてのブロックで同じファイルを同じように使うわけではありません。静的ブロックではsave.jsが重要になり、動的ブロックではrender.phpの内容が表示結果を決めます。

開発用コマンドを実行するときも、なぜビルドが必要なのかを理解しておくと、エラーが出たときに切り分けやすくなります。ソースコードを変更したのに管理画面へ反映されない場合、ブラウザーのキャッシュだけでなく、ビルド済みファイルが更新されているか、ブロックの登録先が正しいかを順番に確認できます。

このように、雛形作成ツールは開発者の理解を省略するものではなく、環境構築のばらつきを減らし、ブロックの仕組みを学ぶための土台を揃えるものとして使うのがよいでしょう。

要件別に見る、静的ブロックと動的ブロックの選び方

ここまでの内容を、実際の設計判断に落とし込んでみます。判断の起点は、ブロックに入力されるデータが「保存後に変化するかどうか」です。

保存後に変化しないなら静的ブロック

編集者が入力した文章や、選択した画像、指定したリンク先を、その投稿の内容として保存したい場合は、静的ブロックが候補になります。

たとえば、サービス紹介ページの料金表や、記事内に置く注意書きは、投稿を更新したときに内容が確定します。訪問するたびにデータベースから再構築する必要はありません。

この場合は、次の流れになります。

1. edit.jsで編集用の入力UIを作る

2. ブロック属性に入力値を保存する

3. save.jsで訪問者向けHTMLを生成する

4. 投稿本文に保存されたマークアップを表示する

5. 将来のHTML変更が過去記事へ影響しないか確認する

ここで最後の工程を省略しないでください。静的ブロックは、保存後のHTMLが残るからこそ、変更管理が重要になります。クラス名やタグ構造を変更する場合は、新規投稿だけではなく、既存投稿を開いて検証する必要があります。

表示時に変化するなら動的ブロック

最新記事一覧や、管理画面で登録したデータを複数のページへ反映するブロックでは、動的ブロックのほうが運用しやすくなります。

この場合は、次のようなプロセスになります。

1. edit.jsで表示条件を設定できるUIを作る

2. カテゴリーや件数などの属性を保存する

3. render.phpまたはrender_callbackでデータを取得する

4. PHP側で表示用HTMLを生成する

5. ページ表示時に最新の内容を出力する

表示内容を一元管理できることが、動的ブロックの大きな利点です。店舗情報を変更したとき、同じブロックを配置したすべてのページへ新しい情報を反映させたいなら、保存済みHTMLを個別に書き換えるよりも、表示時にデータを読むほうが自然です。

ただし、動的ブロックでは、表示処理に依存する範囲が広くなります。PHPのエラー、クエリの負荷、キャッシュの状態、権限による表示条件などを含めて、フロントエンドの結果を確認する必要があります。

判断に迷ったときの5つの質問

実装方式を決めるとき、私は次の質問を順番に確認することをおすすめします。

1. 投稿を保存したあと、表示内容は変化するか

最新記事や現在日時のように変化するなら、動的ブロックを優先して考えます。

2. 過去の記事にも表示変更を一括反映したいか

一括反映が必要なら、PHP側で表示を生成する設計が扱いやすくなります。

3. 編集者が入力した内容を、その時点の記録として残したいか

保存時の状態をコンテンツとして保持したい場合は、静的ブロックが適しています。

4. HTML構造を将来変更する可能性が高いか

静的ブロックではバリデーションへの影響があるため、将来変更が多い機能は慎重に設計します。

5. 表示時のデータ取得やキャッシュを管理できるか

動的ブロックは便利ですが、処理内容によっては表示速度や運用設計まで確認する必要があります。

この質問に答えると、ReactとPHPのどちらを使うかという議論が、ブロックの要件に沿った判断へ変わっていきます。

実装方式を混ぜるときの設計ポイント

編集はReact、表示はPHPという構成

Gutenbergのブロック開発では、編集画面をReactで作り、フロントエンド表示をPHPで生成する構成がよくあります。

たとえば、編集画面ではカテゴリーや表示件数を選択できるようにし、保存するのはその設定値だけにします。そして、訪問者がページを開いたときにPHPが最新の記事を取得し、カード一覧として出力します。

この方法なら、編集者はGutenberg上で設定を変更できます。一方、記事一覧そのものを投稿本文へ固定的に保存する必要はありません。

ただし、編集画面で表示している内容と、フロントエンドでPHPが生成する内容に差が出ることがあります。編集画面ではプレビュー用のデータを表示し、公開画面では別の条件で取得している場合、編集者が見ている状態と訪問者が見る状態が一致しない可能性があります。

そのため、編集画面で何をプレビューし、どこまで実データを反映するのかを決めておくことが大切です。編集UIを作ることだけに集中すると、公開時の表示条件が後から複雑になりやすいので、最初に表示の責任範囲を整理してみましょう。

静的部分と動的部分を分ける

一つのブロックの中に、静的な情報と動的な情報が混在することもあります。

たとえば、編集者が入力した見出しと説明文は静的に保存し、記事一覧だけをPHPで動的に出力する構成です。この場合、すべてを静的にするか、すべてを動的にするかの二択にする必要はありません。

ただし、構造が複雑になるほど、どのデータがどこに保存され、どのタイミングでHTMLになるのかが見えにくくなります。属性の設計書を簡単に作り、次のような情報を整理しておくと、後から確認しやすくなります。

  • 属性名と保存する値
  • 値の型と初期値
  • 編集画面で変更できる場所
  • フロントエンドでの利用箇所
  • 静的に保存する内容か、PHPで取得する内容か
  • 値が空の場合の表示

この整理は、将来の機能追加だけでなく、バリデーションエラーや表示崩れの原因を探すときにも役立ちます。ブロック開発では、ファイル単位の理解だけでなく、データが編集画面から保存、表示まで進むプロセスを追える状態にしておくことが重要です。

失敗しやすい実装パターン

動的な情報を静的に保存してしまう

最新記事や現在年のような情報を静的ブロックとして保存すると、時間が経つほど表示が古くなります。

作成直後は正しく見えていても、数か月後に記事一覧の更新が止まっていることに気づくケースがあります。これは表示処理の問題ではなく、保存時に情報を確定させる方式を選んだことが原因です。

「今は固定表示でよい」と考えて実装する場合でも、そのブロックがどのページで何年使われるのかを考えてみましょう。運用期間が長いサイトでは、更新頻度の低い情報でも、後から変更要件が出てくることがあります。

静的ブロックのHTMLを気軽に変更する

CSSクラスを整理したい、タグをより意味のあるものへ変更したい、余分なラッパー要素を削除したい。このような改善は、開発中によく発生します。

しかし、静的ブロックでは見た目の変更が保存マークアップの変更につながることがあります。既存記事のブロックがバリデーションエラーにならないか、変更後のHTMLと保存済みHTMLが一致するかを確認しなければなりません。

将来も使い続けるブロックであれば、変更を一度に大きく行わず、既存コンテンツへの影響を確認しながら進めてみてください。ブロックのバージョンや移行を考慮する必要がある場合は、最初から変更を前提に属性とマークアップを設計することも有効です。

PHPに処理を集めすぎる

動的ブロックは、表示内容を後から変えやすい方式です。そのため、あれもこれもPHP側で処理したくなることがあります。

しかし、表示時に多くのデータ取得や条件分岐を詰め込むと、どの条件で何が表示されるのかが追いにくくなります。複数のクエリを実行したり、同じ情報をページ内で何度も取得したりすると、サイト全体の負荷にも影響します。

PHPで動的にするべきなのは、保存時に確定できない情報です。編集者が入力した文章まで毎回PHPで再構築する必要があるのか、設定値だけ保存して表示結果を生成すべきなのか、データの性質に応じて分けてみましょう。

開発環境のエラーとブロックのエラーを混同する

ブロック開発では、いくつかの層でエラーが発生します。

  • JavaScriptやReactの構文、コンポーネントに関するエラー
  • ビルド処理や依存パッケージに関するエラー
  • ブロック登録やblock.jsonの設定に関するエラー
  • 静的ブロックのバリデーションエラー
  • PHPの構文やデータ取得に関するエラー
  • フロントエンドのHTMLやCSSに関する表示崩れ

これらを一つの問題として扱うと、原因が見えにくくなります。管理画面でブロックが表示されないのか、編集できないのか、保存後にエラーになるのか、公開画面だけ崩れるのかを最初に分けてください。

エラーが発生した場所を特定できれば、確認するファイルも絞り込めます。仕組みを層ごとに分けて見ることが、トラブルシューティングの再現性を高めます。

Gutenberg自作ブロックの設計を安定させる考え方

ReactとPHPの使い分けで迷ったときは、技術の好みではなく、コンテンツの寿命と更新単位を見てみましょう。

投稿ごとに内容が異なり、編集者が保存した状態をそのまま残したいなら、Reactを使った静的ブロックが基本候補です。edit.jsで入力体験を作り、save.jsで安定したHTMLを出力します。その際、将来のマークアップ変更がバリデーションに影響することを前提に、保存データと表示構造の関係を管理します。

反対に、表示時点で内容が変わるもの、複数のページに同じ最新情報を表示したいものは、PHPによる動的ブロックが適しています。edit.jsでは表示条件を設定できるようにし、render.phpまたはrender_callbackで最新のデータを取得します。

そして、両者を組み合わせる場合は、属性に何を保存するのかを明確にしてみてください。保存するのは、記事一覧そのものではなく、カテゴリーや表示件数のような条件だけにする。編集者が入力した見出しは保存し、関連データだけPHPで取得する。このように役割を分けると、ブロックのプロセスを追いやすくなります。

Gutenbergが導入されたWordPress 5.0以降、ブロックは単なる装飾パーツではなく、編集データと表示ロジックを持つ一つの機能単位になりました。だからこそ、目の前の表示を完成させるだけでなく、保存、再編集、将来の更新、過去記事への影響まで含めて設計する必要があります。

まとめ:選ぶべきなのは技術名ではなくレンダリング方式

Gutenbergの自作ブロックにおけるReactとPHPの違いは、単純な優劣ではありません。

Reactを使った静的ブロックは、編集者が入力した内容を保存し、確定したHTMLとして表示する構成に向いています。編集画面と保存HTMLの役割を分けやすい一方で、save.jsの変更によって過去記事にバリデーションエラーが発生する可能性があります。

PHPを使った動的ブロックは、最新記事一覧や現在日時のように、ページ表示時に変化する情報と相性がよい方式です。表示テンプレートを変更すれば過去記事にも反映できますが、PHPの処理、データ取得、キャッシュ、表示条件まで含めて管理しなければなりません。

Reactなしで構築できるケースもありますが、Gutenbergの編集UIまで完全に独自方式で作る必要があるのか、訪問者向け表示でReactを使わなければよいのかは分けて考えてください。@wordpress/create-blockを使って標準的な開発環境を整え、生成されたファイルの役割を確認しながら進めると、構成の再現性を保ちやすくなります。

まずは、作ろうとしているブロックのデータが保存後に変わるのかを確認してみましょう。変わらないなら静的ブロック、変わるなら動的ブロックを軸に考え、必要に応じてReactによる編集UIとPHPによる表示処理を組み合わせます。

次のステップでは、実際に一つの小さなブロックを選び、属性、edit.jssave.js、またはrender.phpの関係を紙やメモに書き出してみてください。HTMLがどのタイミングで作られ、どこに保存され、いつ再生成されるのかが見えるようになると、Gutenbergのブロック開発はずっと落ち着いて進められるようになります。

Related reading: Gutenbergブロックがデータベースに保存され描画される内部構造 and WordPressカスタムブロック開発はReactかACFか:開発効率と保守性の現実的な落としどころ.

よくある質問

Gutenbergで「このブロックには予期しない変更が加えられています」というエラーが出るのはなぜですか?
保存されているHTMLと、現在のブロック定義から生成されるHTMLが一致しなくなった場合に発生します。タグ構造やクラス名、属性の保存形式などを変更した際に起こりやすい問題です。
静的ブロックと動的ブロックのどちらを選ぶべきですか?
投稿を保存した後に内容が変化しないものは静的ブロック、最新記事一覧のように表示時に最新情報を取得する必要があるものは動的ブロックが適しています。
Reactを使わずにGutenbergのブロックを作ることはできますか?
フロントエンドの表示をReactで構築する必要はありませんが、編集画面のUI構築にはReactベースの環境を使うのが一般的です。PHP主体で構築する場合でも、編集画面での入力体験をどう設計するかによって必要なJavaScriptの量は変わります。
動的ブロックでrender.phpを使うメリットは何ですか?
ページ表示時にHTMLを生成するため、保存済みのHTMLと現在の出力結果を比較するバリデーションエラーを避けやすくなります。また、最新のデータを常に反映できるため、記事一覧などの動的なコンテンツ管理に適しています。

参考情報