WordPress スタティックブロックとダイナミックブロック
スタティックブロックとダイナミックブロックの違いについて。スタティックブロックをダイナミックブロックに変更してその違いを確認しています。
更新日:2025年02月16日
作成日:2025年01月25日
関連ページ
- WordPress 初めてのブロック開発
- WordPress ブロック開発の環境構築(Create Block ツールについての覚書)
- ダイナミックブロックでのデータへのアクセス @wordpress/core-data
- WordPress ダイナミックブロックの作成
スタティックブロックとダイナミックブロックの違い
WordPress には、スタティックブロック(静的ブロック)とダイナミックブロック(動的ブロック)の 2 種類のブロックが用意されています。これら 2 種類のブロックの違いは、フロントエンドでどのようにレンダリングされるかです。
スタティックブロックはブロックエディターでの save プロセス中に静的に生成され、ダイナミックブロックはサーバーサイドで動的に生成されます。
スタティックブロック
スタティックブロック(Static blocks)はページの保存時にコンテンツが静的に固定されるブロックで、ページを保存するときにマークアップがわかっているコンテンツです。
このブロックは HTML マークアップの定義に関して、save() 関数にのみ依存します。
スタティックブロックのわかりやすい例としては、コアの段落ブロックがあります。以下はエディターに表示される段落ブロックの例です。
段落内の単語は、コンテンツ編集者が手動で変更しない限り変更されません。その HTML マークアップは、投稿コンテンツに直接保存されます。
スタティックブロックは JavaScript で記述されます。save() 関数は、ブロックのマークアップを wp_posts データベーステーブル内の投稿の post_content エントリに書き込みます。
上記の段落ブロックをコードエディターで確認すると、段落のマークアップとブロックインジケーターのインラインコメントで構成されています(ブロックのマークアップ表現)。
ブロックインジケーターは、ブロック文法の一部です。WordPress はこれらの HTML コメントを使用して、ブロックとブロックが持つ属性やメタデータを定義します。
WordPress はこれらのコメントを解析して、エディターとフロントエンドの両方でブロックを表示しますが、コメント(ブロックインジケーター)がソースコードにレンダリングされることはありません。
スタティックブロックでは、ソースコードにはブロックインジケーター内のマークアップのみが含まれます。
バリデーションエラー(ブロック検証エラー)
スタティックブロックの save() 関数とデータベースに保存されたコンテンツは密接に関連しています。
投稿エディターは、save() 関数によって作成されたマークアップが、すでにデータベースに保存されているマークアップと同一であることを確認するためにバリデーション(検証)を実行し、違いがある場合は、以下のようなバリデーションエラーを表示します。
開発中はこのバリデーションエラーは頻繁に発生しますが、ブロックを完全に構築し終わったときにバリデーションエラーがなければ問題ありません。
ブロックを構築後に save() 関数を変更すると、既存のブロックの全てで上記エラーが表示され、「復旧を試みる」をクリックして変更を反映させない限り、フロントエンドは更新されません(フロントエンドにエラーは表示されませんが、変更は反映されません)。
そのため、頻繁に save() 関数を更新して変更をすぐにフロントエンドに反映させる必要があるようなブロックでは、代わりにダイナミックブロックを使用することができます。
また、非推奨(deprecated)バージョンを用意して、エディターにバリデーションエラーが表示されるのを回避することができます(ブロックの非推奨プロセス)。
スタティックブロックの利点
スタティックブロックは、JavaScript のみで記述されるためシンプルです。そのマークアップはページが保存される時点でわかっているため、その HTML コードはすべてデータベースに直接保存できます。
このアプローチの方がパフォーマンスが優れています。訪問者がページを表示すると、コンテンツはデータベースから取得されます。サーバー側のレンダリングは必要ないため、ブロックの表示に遅延はありません。
ダイナミックブロック
ダイナミックブロック(Dynamic blocks)は、ページの保存時にそのマークアップと正確なコンテンツがわかっていないコンテンツで、ブロックを含んだ投稿が表示されるタイミングで、ブロックのコンテンツを生成するブロックです。
このブロックには、タイムリーなコンテンツや、サイトの他の部分の変更に依存するコンテンツを含むことができます。ダイナミックブロックのコンテンツは、エディターの介入なしに変更されることが想定されていて、リアルタイムでコンテンツと構造を生成するように設計されています。
その結果、ダイナミックブロックのマークアップはサーバー側でレンダリングされます。
ダイナミックブロックの例としては、サイト名を表示するコアのサイトのタイトルブロックや 最新の投稿を表示する最新の投稿ブロックなどがあります。
サイトのタイトルはサイト設定から変更でき、最新の投稿は新しい投稿が公開されると更新されます。これらのブロックは、ページが保存される時点ではその内容がわからないため、動的である必要があります。
以下はエディターに表示されるサイトのタイトルブロックの例で、このブロックはサイト名を表示します。この例ではタグを h3(H3)に指定し、サイドバーの設定でデフォルトのリンクを無効にしています。
ダイナミックブロックは、投稿の post_content エントリの一部として保存されますが、ブロックのマークアップは変更が予想されるため、ブロックのマークアップはデータベースに保存されません。
ブロックの表現としてデータベースに保存されるのは、ブロックインジケーターだけで構成される1行の HTML で、この HTML は投稿エディターの検証の対象になりません。
フロントエンドユーザーがページにアクセスするたびに、レンダリングメソッドが呼び出されて、ブロックのマークアップが作成されます。
前述の「サイトのタイトルブロック」をコードエディターで確認すると以下のようにブロックインジケーターだけで構成されています。この例の場合、タグを h3 に設定し、リンクを無効にしているので、それらの属性のオブジェクト(level と isLink)が含まれています。
ダイナミックブロックを使うケース
ブロックが、他の投稿、タクソノミー、サイト設定などサイトの他の部分からの情報(ブロックが存在するページ外の情報)に依存している場合は、ダイナミックブロックを使います。
例えば、ブロックに最新の投稿やコメントのリストが含まれている場合や、データベースから取得したデータを使用してブロックのコンテンツが動的に生成される場合などがあります。
また、クラスの追加、HTML 要素の追加、その他の方法によるレイアウトの変更などブロックコードの更新をフロントエンドにすぐに表示する必要がある場合にもダイナミックブロックを使用できます。
スタティックブロックで save() 関数のコードを更新すると、妥当性検証プロセスによりバリデーションエラーが表示されますが、ダイナミックブロックの場合、マークアップ(レンダリングメソッド)を変更しても検証エラーは発生しないので更新をフロントエンドにすぐに表示することができます。
ダイナミックブロックに静的レンダリングを追加
プラグインがサイトから削除されても、コンテンツを残す必要がある場合には、ダイナミックブロックに save() 関数(save.js)を追加して、静的レンダリングを追加することもできます。
ダイナミックブロックでは、ブロックのマークアップと関連した属性はデータベースに保存されますが、HTML 出力は保存されません。
静的にレンダーされるブロックは、常にブロックマークアップ、属性、出力をデータベース内に保存するので、2つを組み合わせ、静的な出力をデータベースに保存しながら、フロントエンドでさらに動的に拡張することもできます。
但し、この方法の場合、スタティックブロック同様、save() 関数のコードを更新すると、妥当性検証プロセスが適用され、エディターにバリデーションエラーが表示されます。
スタティックからダイナミックへ
以下は RichText コンポーネントを使ったユーザーが編集可能な段落を表示する単純なスタティックブロックを作成して、それをダイナミックブロックへ変更する例です。
[注意]以下は、既存のスタティックブロックをダイナミックブロックへ変更する手順ではありません。
スタティックブロックとダイナミックブロックの違いを確認するのが目的ですが、開発段階でブロックのタイプを変更する場合の参考になればと思っています。
この例の場合、スタティックブロックからダイナミックブロックへ変更することで、ブロックの RichText に保存されていたテキストはクリアされるので、すでに挿入済みのすべてのブロックに影響が出ます。
以下は、ローカル環境と Node がインストールされていることを前提にしています。
スタティックブロックを作成
まず、Create Block ツールを使ってスタティックブロックのひな型を作成します。
ターミナルでプラグインディレクトリ(wp-content/plugins)に移動して以下を実行します。
% npx @wordpress/create-block@latest sample-block
プラグインディレクトリの中に以下のようなブロックのディレクトリ sample-block が作成されます。
プラグインを有効化
管理画面のプラグインページでプラグイン sample-block を有効化します。
開発を開始
ターミナルでディレクトリ sample-block に移動し、npm start コマンドを実行して開発を開始します。
block.json
RichText コンポーネントでは、ユーザーが入力するテキストを保存する必要があるので、block.json でユーザーが入力する文字列を保存する content という属性を attributes プロパティに追加します。
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "create-block/sample-block",
"version": "0.1.0",
"title": "Sample Block",
"category": "widgets",
"icon": "smiley",
"description": "Example block scaffolded with Create Block tool.",
"example": {},
"supports": {
"html": false
},
"attributes": {
"content": {
"type": "string",
"source": "html",
"selector": "p"
}
},
"textdomain": "sample-block",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}
edit.js
edit.js を以下のように書き換えます。
RichText コンポーネントをインポートし、Edit 関数のパラメータに属性(attributes)と属性を更新する関数(setAttributes)を分割代入で受け取ります。
そして Edit() 関数によって return される JSX に RichText コンポーネントを追加します(もとのブロックのラッパー要素の p 要素を RichText コンポーネントで置き換えます)。
その際、useBlockProps() を RichText コンポーネントに展開します。また、RichText コンポーネントの tagName プロパティには p を指定して入力エリアを p 要素としてレンダリングします。
import { __ } from "@wordpress/i18n";
// RichText のインポートを追加
import { useBlockProps, RichText } from "@wordpress/block-editor";
import "./editor.scss";
// RichText コンポーネントを追加
export default function Edit({ attributes, setAttributes }) {
return (
<RichText
{...useBlockProps()}
tagName="p"
onChange={(value) => setAttributes({ content: value })}
value={attributes.content}
placeholder="Enter some text ..."
/>
);
}
投稿に作成中のブロック sample-block を挿入すると以下のように RichText コンポーネントの placeholder プロパティに指定したテキスト「Enter some text ...」が表示されます。
ブロックにはテキストを入力することができますが、何を入力して保存しても、コードエディターで確認すると以下のように表示されます。
これは、Create Block ツールで自動的に生成された以下のひな型の save.js によるものです。
import { useBlockProps } from '@wordpress/block-editor';
export default function save() {
return (
<p { ...useBlockProps.save() }>
{ 'Sample Block – hello from the saved content!' }
</p>
);
}
save() 関数により、上記のブロックのマークアップが wp_posts データベーステーブル内の投稿の post_content エントリに書き込まれて保存されています。
そのため、この時点でエディターでブロックのテキストを変更して保存しても、再読込すると以下のように save() 関数により保存されたマークアップが表示されます。
save.js
RichText コンポーネントのコンテンツが保存されるように save.js を以下のように書き換えます。
edit.js と同様に RichText コンポーネントをインポートし、save() 関数のパラメータに attributes を受け取ります。
return() ステートメントの JSX を p 要素から RichText コンポーネントに変更し、Edit() 関数の場合と同様、スプレッド構文を使って useBlockProps.save() を RichText コンポーネントに展開します。
これで、RichText コンポーネントのマークアップとエディターで入力された文字列(attributes.content)がデータベースに保存されます。
// RichText のインポートを追加
import { useBlockProps, RichText } from "@wordpress/block-editor";
export default function save({ attributes }) {
// RichText.Content (JSX) を返す
return (
<RichText.Content
{...useBlockProps.save()}
tagName="p"
value={attributes.content}
/>
);
}
例えば、エディターで任意の文字列を入力して保存すると例えば以下のように表示されます。
コードエディターでも入力された文字列が表示されます。
フロントエンドも保存した内容が出力されます。
save.js を変更
save.js を変更することで、バリデーションエラーが発生する例です。
この例では、ブロックのラッパー要素にクラス foo を追加する変更を加えます。
変更がわかりやすいように、style.scss を以下のように書き換えておきます。
.wp-block-create-block-sample-block {
background-color: #21759b;
color: #fff;
padding: 2px;
}
/* 追加 */
.wp-block-create-block-sample-block.foo {
background-color: red;
}
edit.js を以下のように書き換えてブロックのラッパー要素にクラス foo を追加します(8行目)。
ラッパー要素に追加の属性が必要であれば、属性を定義するオブジェクトを useBlockProps() に引数として渡します。
import { __ } from "@wordpress/i18n";
import { useBlockProps, RichText } from "@wordpress/block-editor";
import "./editor.scss";
export default function Edit({ attributes, setAttributes }) {
return (
<RichText
{...useBlockProps({className: 'foo'})}
tagName="p"
onChange={(value) => setAttributes({ content: value })}
value={attributes.content}
placeholder="Enter some text ..."
/>
);
}
エディターを確認すると、クラス foo を追加したので背景色が赤色に変わります。
フロントエンドにも反映されるように save.js も同様に以下のように書き換えます。
import { useBlockProps, RichText } from "@wordpress/block-editor";
export default function save({ attributes }) {
return (
<RichText.Content
{...useBlockProps.save({className: 'foo'})}
tagName="p"
value={attributes.content}
/>
);
}
エディターを再読込して確認すると、save() 関数が変更されたので、以下のようにバリデーションエラーが表示されます。
フロントエンド側はエラーはありませんが、変更が反映されていません。
エディターで「復旧を試みる」をクリックすると、ブロックは正常に表示されます。そして投稿を保存すると、フロントエンド側にも変更が反映されます。
このように、スタティックブロックでは save() 関数を変更すると、既存のブロックでバリデーションエラーが表示され、「復旧を試みる」をクリックし、投稿を保存しない限り、フロントエンドは更新されません。
ダイナミックブロックへ変更
ダイナミックブロックを作成するには以下の 2 つの方法があります。
- register_block_type() 関数で render_callback に、ブロックの表示内容を生成するコールバック関数を指定する(従来の方法)
- block.json に render プロパティを追加し、ブロックの表示内容を出力する PHP ファイルを指定する(WordPress v6.1 以降でサポート)
この例では2番目の方法を使って、前述のスタティックブロックをダイナミックブロックに変更します。
[注意] 以下を行うと、RichText コンポーネントに保存されていたテキストは失われます。
block.json
block.json に以下のように render プロパティを追加します。
ブロックの表示内容を出力する PHP ファイルの名前は任意ですが、この例では render.php としています。
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "create-block/sample-block",
"version": "0.1.0",
"title": "Sample Block",
"category": "widgets",
"icon": "smiley",
"description": "Example block scaffolded with Create Block tool.",
"example": {},
"supports": {
"html": false
},
"attributes": {
"content": {
"type": "string",
"source": "html",
"selector": "p"
}
},
"textdomain": "sample-block",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js",
"render": "file:./render.php"
}
render.php
src/sample-block ディレクトリに block.json の render プロパティに指定した render.php という名前の PHP ファイルを作成します(npm start で開発モードにしていれば、自動的に build/sample-block ディレクトリにも render.php が生成されます)。
render.php に以下を記述します。
render プロパティに指定した PHP ファイルや render_callback に指定したコールバック関数では、以下のデータを自動的に受け取ります。
- $attributes: ブロックの属性の配列
- $content: データベース内に保存されたブロックのマークアップ(もしあれば)
- $block: レンダリングされたブロックを表す WP_Block クラスのインスタンス
ブロックのラッパー要素の属性を取得するには、get_block_wrapper_attributes() を使います。
get_block_wrapper_attributes() のパラメータに id、class、style キーを持つ連想配列を指定することで、ラッパー要素にそれらの属性を追加することができます。以下では save.js と同じようにブロックのラッパー要素(p 要素)にクラス foo を追加しています。
ブロックの属性にアクセスするには $attributes(連想配列)を使います。コンテンツには content 属性の値を出力するように $attributes['content'] を echo します。
<?php
$wrapper_attributes = get_block_wrapper_attributes( ['class' => 'foo'] );
?>
<p <?php echo $wrapper_attributes; ?>>
<?php echo $attributes['content']; ?>
</p>
この時点でフロントエンドを確認すると、以下のように Warning: Undefined array key content(配列のキー content が未定義)というエラーが表示されます。
確認のため render.php に var_dump($attributes);
を記述してみると、array(0) { }
が出力され、$attributes 配列が空になっているのが確認できます。
これは、block.json に設定している attributes プロパティの content 属性で、以下のように source フィールドを指定しているためです。
"attributes": {
"content": {
"type": "string",
"source": "html",
"selector": "p"
}
}
試しに、attributes プロパティに以下のようなテスト用の属性 test を追加してフロントエンドを確認すると、var_dump($attributes);
により、array(1) { [“test”]=> string(4) “test” }
のように追加した test 属性は問題なく render.php で受け取ることができます。
"attributes": {
"content": {
"type": "string",
"source": "html",
"selector": "p"
},
"test": {
"type": "string",
"default": "test"
}
},
var_dump() を記述している場合は削除し、block.json を以下のように書き換えます。
PHP でレンダリングされるブロックでは、block.json で source フィールドを使用している場合はそれらを削除します。この場合、selector の設定も不要なので削除します。
これにより render.php では $attributes['content'] を受け取ることができます。
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "create-block/sample-block",
"version": "0.1.0",
"title": "Sample Block",
"category": "widgets",
"icon": "smiley",
"description": "Example block scaffolded with Create Block tool.",
"example": {},
"supports": {
"html": false
},
"attributes": {
"content": {
"type": "string"
}
},
"textdomain": "sample-block",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js",
"render": "file:./render.php"
}
エディターを再読込すると、以下のようなバリデーションエラーが表示されるので「復旧を試みる」をクリックして復旧します。
保存されていたテキストはクリアされ、以下のように初期状態のブロックになります。
ブロックにテキストを入力して保存してみます。
これでフロントエンド側も問題なく表示されます。
コードエディターに切り替えて確認すると、ブロックコメントに {"content":"New Text"} が追加されていますが、save.js がまだあるので save() 関数により p 要素のマークアップが含まれています。
もし、この時点でブロックのプラグインを無効化すると、以下のように「HTML として保存」というボタンが表示され、ボタンをクリックすると save() 関数により保存されているマークアップに変換されます。
index.js
save.js を残しておくと、save() 関数によりブロックのマークアップを保存することができますが、save() 関数を変更するとバリデーションエラーが発生します。
この例では save.js を残しておく必要はないので、index.js を以下のように書き換えます。そして save.js を削除します。
import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import Edit from './edit';
//import save from './save'; // 削除
import metadata from './block.json';
registerBlockType( metadata.name, {
edit: Edit,
//save, // 削除
} );
エディターを再読込するとバリデーションエラーが発生するので「復旧を試みる」をクリックします。
ブロックが復旧されます。
コードエディターに切り替えて確認すると、以下のように p 要素のマークアップはなくなり、属性のオブジェクトを含むブロックコメントのみの構成になっています。
このため、もし、プラグインを無効化すると以下のように表示され、「HTML として保存」というオプションは表示されず、マークアップを残すことはできません。
これでダイナミックブロックへの変更は完了です。
例えば、edit.js を以下のように書き換えて、ブロックラッパーからクラス foo を削除し、
import { __ } from "@wordpress/i18n";
import { useBlockProps, RichText } from "@wordpress/block-editor";
import "./editor.scss";
export default function Edit({ attributes, setAttributes }) {
// {...useBlockProps({className: 'foo'})} を {...useBlockProps()} に変更
return (
<RichText
{...useBlockProps()}
tagName="p"
onChange={(value) => setAttributes({ content: value })}
value={attributes.content}
placeholder="Enter some text ..."
/>
);
}
render.php を以下のように書き換えて、同様にブロックラッパーからクラス foo を削除します。
<?php
// get_block_wrapper_attributes( ['class' => 'foo'] ); を以下に変更
$wrapper_attributes = get_block_wrapper_attributes();
?>
<p <?php echo $wrapper_attributes; ?>>
<?php echo $attributes['content']; ?>
</p>
新たにブロックを挿入すると、foo クラスが削除されたので背景色が変わり、例えば、以下のように表示されます(バリデーションエラーは発生しません)。
フロントエンド側は以下のように表示されます。
※ 1つ目のブロックは index.js で save の変更前に作成されたブロックのため、その時点でのクラス属性がブロックコメントの属性オブジェクトに残ってしまっています。
以下は、更にブロックを追加した場合の、コードエディターでの表示例です。
後からブロックのタイプを変更する場合、上記のように既存のブロックに影響が出る可能性があります。
リファレンス
参考ページ