GutenbergのブロックをAdvanced Custom Fields的に使ってみる

Gutenbergにはテンプレート機能があり、利用するブロックを制限することが可能です。このテンプレート機能を使うことで、「Advanced Custom FieldsAdvanced Custom Fields」でやっていたような限定的な入力欄をブロック上に再現することができるようになりました。

この記事では、Gutenbergにはテンプレート機能を使って店舗情報を繰り返すといったエディタを作ってみます。

今回紹介する内容ともっとも近いWordPressドキュメントになります。こちらも合わせてご確認ください! → Templates | Block Editor Handbook

はにわまん

GutenbergでWordPressでできることの幅がどんどん広がっていますね!

Gutenbergのブロックテンプレートの作成方法

前提として、Gutenbergのブロックテンプレートは特定の投稿タイプに紐づけて使うことができます。ですので、「特定の固定記事に限って使う」みたいな使う方ができない点だけご注意ください。

作成の流れとしては、大きくは2つ。

  • テンプレートにしたいブロックの作成
  • 投稿タイプ作成時にテンプレートを指定

任意のブロックを使うためにはブロック作成するスキルが必要になるので、まずはブロック作成スキルから身につける必要があります。ブロックの作り方については公式チュートリアル公式チュートリアルや、自分の基本の作り方を参考にしてください。

今回は、冒頭で紹介した以下の3つが固定の入力欄として用意されているブロックを作成しようと思います。

  • 画像
  • タイトル
  • 紹介文

また、Advanced Custom Fieldsの繰り返しフィールドのように、自由に増減できるような作りにもしています。

それでは、早速作っていきましょう!基本的なGutenbergブロックの作り方についてまずは以下を参考にしてもらえたらと思います。
https://haniwaman.com/block-edit/

今回は以下のような構成でGutenberg用のブロックプラグインを作っていきます。フォルダ名は「my-block」としました。

  • index.php・・・プラグインのメインファイル
  • style.css・・・表示用のCSS
  • editor.css・・・エディタ用のCSS
  • block-store.js・・・店舗ブロック
  • block-stores.js・・・店舗ブロックを繰り返すブロック

ブロックの定義

長くなりすぎるの全部のコードは割愛しますが、my-storesという「店舗ブロックを繰り返すブロック」と、my-storeという「店舗ブロック」を定義しています。

関連するCSSファイルやjavaScriptファイルの指定については「Gutenbergにオリジナルなブロックを作成する方法(静的編)Gutenbergにオリジナルなブロックを作成する方法(静的編)」をご参考ください。

<?php
/**
 * Plugin Name: My Block
 */

function my_block_example() {

	// ブロック用のスクリプトを登録
	wp_register_script(
		'my-block-script-stores',
		plugins_url( 'block-stores.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element', 'wp-editor' ),
		'1.0.0',
		true
	);

	// ブロック用のスクリプトを登録
	wp_register_script(
		'my-block-script-store',
		plugins_url( 'block-store.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element', 'wp-editor' ),
		'1.0.0',
		true
	);

	// CSSの読み込み割愛
	// 「my-block-style-editor」と「my-block-style-front」の読み込みが入ります。

	// ブロックの定義を登録
	register_block_type(
		'my-block/my-stores',
		array(
			'editor_script' => 'my-block-script-stores',
			'editor_style'  => 'my-block-style-editor',
			'style'         => 'my-block-style-front',
		)
	);

	// ブロックの定義を登録
	register_block_type(
		'my-block/my-store',
		array(
			'editor_script' => 'my-block-script-store',
			'editor_style'  => 'my-block-style-editor',
			'style'         => 'my-block-style-front',
		)
	);
add_action( 'init', 'my_block_example' );

店舗ブロックの作成

まずは「my-block-script-store」に店舗ブロックを作成していきましょう。ちょっと長くなりますが全コードです。ポイントとしては以下の3点かと思います。

  • HTML構造のイメージでエレメントを入れ子で作成
  • attributesselectorをクラスで探させる
  • 画像のブロックは既存のブロックを活用(作るのが面倒くさそうだったので…)
( function( blocks, editor, element, blockEditor ) {
	var el = element.createElement;
	var InnerBlocks = blockEditor.InnerBlocks;
	var RichTextTitle = editor.RichText;
	var RichTextContent = editor.RichText;

	const MY_STORE_IMAGE = [
    [ 'core/image', {} ],
	];

	blocks.registerBlockType( 'my-block/my-store', {
			title: '店舗情報',
			category: 'layout',
			attributes: {
				title: {
					type: 'array',
					source: 'children',
					selector: '.store-title',
				},
				content: {
					type: 'array',
					source: 'children',
					selector: '.store-content',
				},
			},
			edit: function( props ) {
				var title = props.attributes.title;
				var content = props.attributes.content;

		    function onChangeTitle( newTitle ) {
			    props.setAttributes( { title: newTitle } );
				}

		    function onChangeContent( newContent ) {
			    props.setAttributes( { content: newContent } );
				}

				return el(
					'div',
					{ className: 'store' },
					el( 'div',
						{ className: 'store-img' },
						el( InnerBlocks,
							{
								template: MY_STORE_IMAGE,
								templateLock: "all",
							} )
					),
					el( 'div',
						{ className: 'store-body' },
						el( RichTextTitle, {
							tagName: 'div',
							className: 'store-title',
							placeholder: '店舗タイトル',
							onChange: onChangeTitle,
							value: title,
						} ),
						el( RichTextContent, {
							tagName: 'p',
							className: 'store-content',
							placeholder: '店舗紹介文',
							onChange: onChangeContent,
							value: content,
						} ),
					)
				)
			},

			save: function( props ) {

					return el(
						'div',
						{
							className: 'store',
						},
							el( 'div',
								{
									className: 'store-img'
								},
								el( InnerBlocks.Content )
							),
							el( 'div',
								{
									className: 'store-body',
									value: props.attributes.body
								},
								el( RichTextTitle.Content, {
									tagName: 'div',
									className: 'store-title',
									value: props.attributes.title,
								} ),
								el( RichTextContent.Content, {
									tagName: 'p',
									className: 'store-content',
									value: props.attributes.content,
								} ),
							)
					);
			},
	} );
} (
	window.wp.blocks,
	window.wp.editor,
	window.wp.element,
	window.wp.blockEditor,
) );

このブロックを追加すると、エディタ上に反映されることが分かると思います。テンプレート的に使うというより一般的に使えるブロックとしての活用が可能です。

ブロックのレイアウトから選択できるようになります。

選択すると、画像とタイトル、紹介文が入力可能なブロックが登場します。

店舗ブロックを繰り返すブロックの作成

GutenbergにはInnerBlocksというブロックの中に複数のブロックを設置可能な機能が用意されています。詳しくは公式をご参照ください。
Nested Blocks: Using InnerBlocks | Block Editor Handbook

InnerBlocksには、中身に配置できるブロックを制限できる機能が備わっています。この機能を活用して先ほど作成したmy-block/my-storeしか配置できないブロックを作成していくといった流れです。

ポイントは以下の3点です。

  • ALLOWED_BLOCKSで配置可能なブロックの指定
  • allowedBlocks: ALLOWED_BLOCKSでInnerBlocksのブロック制限
  • templateLock: falseでInnerBlocks内の複数設置を可能にする
( function( blocks, element, blockEditor ) {
	var el = element.createElement;
	var InnerBlocks = blockEditor.InnerBlocks;
	const ALLOWED_BLOCKS = [ 'my-block/my-store' ]

	blocks.registerBlockType( 'my-block/my-stores', {
			title: '店舗リスト',
			category: 'layout',

			edit: function( props ) {
					return el(
							'div',
							{
								className: props.className,
							},
							el( InnerBlocks,
								{
									allowedBlocks: ALLOWED_BLOCKS,
									templateLock: false,
								}
							)
					);
			},

			save: function( props ) {
					return el(
							'div',
							{ className: props.className },
							el( InnerBlocks.Content )
					);
			},
	} );
} (
	window.wp.blocks,
	window.wp.element,
	window.wp.blockEditor,
) );

作成できたら、このブロックの動きを見てみましょう!ブロックから「店舗リスト」が増えていますね。

そしていくつでも店舗ブロックが増やせるような動きとなっています。

投稿タイプのブロック制限

最後に特定の投稿タイプは、先ほど作成した店舗ブロックの増減可能なブロックだけを使えるようにしてあげれば、他の余計なブロックを触らせることなく、店舗の追加、入力、削除のみに集中させることができるようになります!

基本通りに投稿タイプを追加してもらいつつ、ポイントとしては、templateのパラメーターの部分ですね。

  • 投稿タイプで許可するブロックの種類(複数可)
  • template_lockで操作の許容範囲の指定
function my_post_type_shop() {
	register_post_type(
		'shop',
		[
			'label'         => '店舗',
			'public'        => true,
			'show_in_rest'  => true,
			'template'      => [
				[
					'my-block/my-stores',
					[
						'placeholder' => '店舗情報を入れてください',
					],
				],
			],
			'template_lock' => 'insert',
		]
	);
};
add_action( 'init', 'my_post_type_shop' );

template_lockに指定できるのはall(完全に操作は不可にする)とinsert(追加等は不だが可移動は可能)の2種類があります。今回は、移動させたいと思ったので、insertとしています。

ここまでで「店舗」という投稿タイプが追加され、ブロックの選択は不可能となり、店舗を繰り返すブロックだけが常に表示されているような状態となりました。

入力項目は固定で、追加したり移動したり削除したりといったことが容易にできる投稿タイプの完成です。

おわり

GutenbergのブロックをAdvanced Custom Fields的に使う方法でした。特にリピートグリッドはAdvanced Custom Fieldsでも人気の機能だと思いますが、Gutenbergでは視覚的にもよりイメージしやすく提供することが可能です。

ただしAdvanced Custom Fieldsと比べるとブロックの作り方等の知識が必要になるので、誰もができる選択肢ではないかもしれませんね…。

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

WordPressが得意なWeb屋。HPcode代表。

300件以上のWordPressカスタマイズを対応してきました。SE → 農家 → アフィリエイター → Web屋。生まれは三重県。