テーブルブロックを投稿メタ(カスタムフィールド)に保存する

説明

ふと「テーブルブロックの内容を投稿メタ(カスタムフィールド)として保存できたら便利なのでは」と思い、投稿メタの使い方を調べてみた。

投稿メタの登録を忘れずに

参考にしたのはブロックエディターハンドブックの「投稿メタをブロックで保存」。この記事は投稿メタ用の専用ブロックを作成して投稿メタを更新するものだったが、今回は少しアレンジしてテーブルブロックに応用。前回の「テーブルの1列目をth要素にしてみる」を拡張することにした。

まずはPHP部分。ブロックエディターで投稿メタを使用するには register_post_meta関数で登録する必要がある。

function my_register_post_meta() {
	register_post_meta( 'post', 'item_addr', array(
		'show_in_rest' => true,
		'single' => true,
		'type' => 'string',
	) );
	register_post_meta( 'post', 'item_price', array(
		'show_in_rest' => true,
		'single' => true,
		'type' => 'string',
	) );
}

add_action( 'init', 'my_register_post_meta' );

ここでのポイントは第3パラメータで、連想配列のキー'show_in_rest'の値はtrue(または同等の連想配列)を指定すること。どうやらブロックエディターはREST APIを利用して投稿メタデータをやりとりするようだ。

JavaScript側は、「その他の設定」パネルの中に「投稿メタを保存」ボタンを追加し、そのボタンが押された時にテーブルブロックの内容を投稿メタとして保存するもの。ソースコードは次のような感じだ。

( function ( wp ) {
	var el = wp.element.createElement;

	const extendCoreBlocks = wp.compose.createHigherOrderComponent(
		function ( BlockEdit ) {
			return function ( props ) {
				const {
					name,
					attributes,
					setAttributes,
					isSelected,
				} = props;

				if ( isSelected && 'core/table' === name ) {
					attributes.column1_th = false;

					if ( 0 < attributes.body.length && 'string' === typeof attributes.body[0].cells[0].tag ) {
						attributes.column1_th = ( 'th' === attributes.body[0].cells[0].tag );
					}

					function onToggleColumn1() {
						let newBody = attributes.body;
						for ( let row = 0; row < newBody.length; row++ ) {
							if ( attributes.column1_th ) {
								newBody[row].cells[0].tag = 'td';
								newBody[row].cells[0].scope = undefined;
							} else {
								newBody[row].cells[0].tag = 'th';
								newBody[row].cells[0].scope = 'row';
							}
						}

						setAttributes( {
							column1_th: ! attributes.column1_th,
							body: newBody,
						} );
					}

					const postType = wp.data.useSelect(
						( select ) => select( 'core/editor' ).getCurrentPostType(),
						[]
					);
					const [ meta, setMeta ] = wp.coreData.useEntityProp( 'postType', postType, 'meta' );

					if ( 'post' === postType  &&
						2 <= attributes.body.length &&
						2 <= attributes.body[0].cells.length &&
						( meta['item_addr'] !== attributes.body[0].cells[1].content ||
						meta['item_price'] !== attributes.body[1].cells[1].content ) ) {
						setMeta( { ...meta,
							'item_addr': attributes.body[0].cells[1].content,
							'item_price': attributes.body[1].cells[1].content
						} );
					}

					return el(
						wp.element.Fragment,
						{},
						el( BlockEdit, props ),
						el(
							wp.blockEditor.InspectorControls,
							{},
							el(
								wp.components.PanelBody,
								{
									title: 'その他の設定',
									initialOpen: true,
								},
								el(
									wp.components.ToggleControl,
									{
										label: 'tbody内の第1列をth要素にする',
										help: attributes.column1_th?
											'第1列はth要素。': '第1列はtd要素。',
										checked: attributes.column1_th,
										onChange: onToggleColumn1,
									}
								)
							)
						)
					);
				}
				return el( BlockEdit, props );
			};
		},
		'extendCoreBlocksControl'
	);

	wp.hooks.addFilter(
		'editor.BlockEdit',
		'core-extend/table-block',
		extendCoreBlocks
	);
} )( window.wp );

青字の部分では、wp.dataパッケージのuseSelect関数を使って編集中の投稿タイプを取得。次のwp.coreDataパッケージのuseEntityProp関数は、ブロックエディターで投稿メタデータを使用するためのもので、現在の投稿メタデータ(meta)と投稿メタデータを保存するための関数(setMeta)を取得できる。赤字の部分では、今回投稿タイプ'post'を指定して投稿メタを登録していることを踏まえ、投稿タイプが'post'で現在の投稿メタデータとセルの内容が異なる場合のみ投稿メタデータを更新できるようにした。

実際にmetaの内容を確認してみる。

{item_addr: '', item_price: ''}

どちらも初期値が''になっているが、これはPHPのregister_post_meta関数でキー'type'の値に'string'を指定し、キー'default'が省略されているためである。それぞれキーの値しだいでこの初期値は変わるようだ。念のため、ここでデータベース(wp_postmetaテーブル)を確認してみたが、それらしいデータは何も保存されていなかった。

mysql> select * from wp_postmeta where post_id=443 and meta_key like 'item_%';
Empty set (0.02 sec)

投稿メタデータが保存されるタイミング

上記のコードでは、テーブル内のセルが更新される度にsetMeta関数を呼び出し、投稿メタデータを更新するようにしている。実際にテーブルブロックの1行目・2列目のセルに'横浜市'を、2行目・2列目のセルに'1250'を入力してみると、metaの内容は次のように変わった。

{item_addr: '横浜市', item_price: '1250'}

この後も各セルを繰り返し編集し、その都度metaの内容に反映されていることを確認できた。

ここでmetaに保存されている投稿メタデータがデータベースへ保存されているかを確認する。

mysql> select * from wp_postmeta where post_id=443 and meta_key like 'item_%';
Empty set (0.02 sec)

どうやらsetMeta関数を呼び出して更新されるのはメモリーだけで、すぐにデータベースへ保存されるわけではないようだ。

ブロックエディターハンドブックをざっと見た限りプログラム要素は他になかったのだが、もう一度読み直すと「下書き、あるいは公開状態で投稿を保存すると、投稿メタ値も保存されます。」と記載されている。ということで、画面上部にある「更新」ボタンがクリックしてデータベースを確認する。

mysql> select * from wp_postmeta where post_id=443 and meta_key like 'item_%';
+---------+---------+------------+------------+
| meta_id | post_id | meta_key   | meta_value |
+---------+---------+------------+------------+
|     434 |     443 | item_addr  | 横浜市     |
|     435 |     443 | item_price | 1250       |
+---------+---------+------------+------------+
2 rows in set (0.00 sec)

無事、投稿メタデータがデータベースに保存された。ブロックエディターで投稿メタデータを保存するには、明示的に「更新」ボタンをクリックするような投稿データを保存するアクションが必要になることがわかった。


今回はテーブルブロックのデータを投稿メタデータとして保存してみた。ふとした思いつきで始まり、クラシックエディターの「カスタムフィールド」とかなり勝手が違っていたが、無事実装することができたのはなによりだ。ブロックエディターで投稿メタデータを使う方法として、既存のブロックを活用するのも悪くないのではないだろうか。


最終更新 : 2022年01月05日 12:15


お勧め

update_site_option(2018年5月27日 更新)

bool update_site_option( string $option, mixed $default )
サイトオプションの値を更新する。

is_privacy_policy(2019年5月8日 更新)

bool is_privacy_policy()
要求されているページが、プライバシーポリシーページか調べる。

wp_check_password(2013年5月22日 更新)

bool wp_check_password( string $password, string $hash [ , mixed $user_id = '' ] )
ユーザのログインパスワードか調べる。

wp_playlist_shortcode(2014年4月20日 更新)

string wp_playlist_shortcode( array $attr )
playlistショートコードの出力HTMLを生成する。

current_user_can(2018年5月27日 更新)

bool current_user_can( string $capability [, mixed $args ] )
現在のユーザーがパラメータ$capabilityで指定した権限(または役割)を所有しているか調べる。