WordPressのブロックをテンプレートの任意の位置に振り分けて表示する方法
WordPressのクラシックテーマで制作しているWebサイトにおいて、1ページの中でブロックの表示位置を振り分ける方法について紹介しています。
テンプレートの任意の位置にGutenbergブロックを呼び出せるため、カスタムフィールドの代わりにブロックでコンテンツを管理したい場合に有効な方法です。
どのようなケースか
次の画像はカスタムブロックを2箇所に挿入したページです。

背景色グレーのセクションが3つあり、最初のセクションに「ブロックA」を、最後のセクションに「ブロックB」のカスタムブロック(黒背景に白文字のテキスト)を挿入しています。カスタムブロック以外のHTMLは全てテンプレートに直接記述しています。
エディタでは次のようになっています。2つのブロックを挿入しただけのシンプルな画面です。

この方法は、ページ全体はテンプレートで構成しつつ、特定のセクションのみ編集可能にしたい場合に有効です。企業サイトを例にすると以下のようなイメージです。
- 企業情報 ← 固定- 実績 ← ブロックを活用したい- サービス内容 ← 固定- お客様の声 ← ブロックを活用したい- お問い合わせ ← 固定本文を表示する<?php the_content(); ?>では、ブロックをセクションごとに分割して表示することは困難です。そこで今回の方法の出番となります。
動的に変更したい箇所が複数ある場合、カスタムフィールドを使うケースも多いかと思いますが、ブロックで管理したい場合や繰り返しフィールドが使えない環境では、この方法が有効な選択肢になり得ます。
実装例
早速ですが以下が実装に使用したコードです。
/** * 指定したブロック名のブロックだけを出力するヘルパー関数 * * @param array $blocks parse_blocks()で得られるブロック配列 * @param string $block_name 抽出したいブロック名(例: 'lazyblock/block-a') * * @return void */
function render_blocks_by_name($blocks, $block_name) { foreach ($blocks as $block) { if ($block['blockName'] === $block_name) { echo render_block($block); } }}<?php$content = get_the_content();$blocks = parse_blocks($content);?>
<section> <h2>見出し</h2> <?php render_blocks_by_name($blocks, 'lazyblock/block-a'); ?></section><section> <h2>見出し</h2> <p>テキストが入ります。テキストが入ります。テキストが入ります。</p></section><section> <h2>見出し</h2> <?php render_blocks_by_name($blocks, 'lazyblock/block-b'); ?></section>ヘルパー関数をfunctions.phpで定義し、テンプレート側でその関数を呼び出しています。コードのポイントを順に説明します。
ブロックデータの取得
テンプレートの冒頭でget_the_content()で投稿本文を取得し、parse_blocks()でブロック構造の配列に変換しています。この処理は1回のみ行い、以降は変数$blocksを使い回します。
ブロックの出力
render_blocks_by_name()関数は、$blocksの中から引数で指定したブロック名(例:lazyblock/block-a)と一致するブロックを抽出し、render_block()でHTMLとして出力します。テンプレートの表示したい箇所でこの関数を呼び出すだけで、対象のブロックを任意の位置に配置できます。
今回はLazy Blocksのカスタムブロックを使用していますが、コアブロックでも同様に機能します。
動作確認環境
以下の環境において動作を確認しました。
- WordPress 6.9.4(クラシックテーマ)
- PHP 8.0.0
- Lazy Blocks 4.2.1
注意点
実装時の注意点を以下にまとめます。
ブロックが挿入されていない場合
エディタに対象のブロックが挿入されていない場合、foreach内の条件に一致しないため何も出力されません。エラーは発生しませんが、必須のコンテンツであればフォールバックを用意しておくと安全でしょう。
同じブロックが複数挿入されている場合
同じblockNameのブロックが複数挿入されている場合は、すべてが同じ位置に出力されます。1つだけ表示したい場合はループ内でbreakを追加するなどの対応が必要です。
この方法のメリット・デメリット
メリットとデメリットをまとめると次のようになります。
| メリット | デメリット |
|---|---|
|
|
今回の方法は、ブロックを「レイアウト要素」ではなく「コンテンツデータ」として扱う設計とも言えます。
カスタムフィールドとの比較
冒頭でも触れましたが、カスタムフィールドの繰り返し機能を使用できない現場ではかなり有効な方法だと感じています。両者を比較すると次のようになります。
| 観点 | カスタムフィールド(ACF等) | 今回の方法(parse_blocks) |
|---|---|---|
| データの保存先 | postmeta | post_content(投稿本文) |
| 編集UI | フィールド専用のフォーム | ブロックエディタ |
| コンテンツの自由度 | フィールドの型に依存する | ブロックで表現できる範囲で自由 |
| 繰り返しコンテンツ | 繰り返しフィールド(Pro / 有料) | ブロックの追加で対応可能 |
| 導入コスト | フィールド定義+テンプレート実装 | ブロック追加+テンプレート実装 |
| エディタの見た目 | フォーム形式(実際の表示とは異なる) | ブロックの実装による(Lazy Blocks無料版の場合はフォーム形式) |
| プラグイン依存 | Advanced Custom Fields等が必要 | ブロック作成にLazy Blocks等が必要(コアブロックのみなら不要) |
まとめ
parse_blocks()とrender_block()を組み合わせることで、クラシックテーマのテンプレート内の任意の位置にブロックを表示することができました。ブロックの編集体験を活かしたい際に有効な方法です。
デメリットを把握したうえで適切な場面で使用していきたいです。
