この記事は最後に更新してから1年以上経過しています。

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

説明

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

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

参考にしたのはブロックエディターハンドブックの「投稿メタをブロックで保存」。この記事は投稿メタ用の専用ブロックを作成して投稿メタを更新するものだったが、今回は少しアレンジしてテーブルブロックに応用。前回の「テーブルの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


お勧め

get_next_image_link(2021年7月25日 更新)

string get_next_image_link( [ string | int[] $size = 'thumbnail' [ , string | false $text = false ] ] )
次の添付ファイルへのリンクを取得する。

wp_after_insert_post(2020年12月11日 更新)

void wp_after_insert_post( int | WP_Post $post, bool $update, WP_Post $post_before )
投稿情報を保存した後にアクションを実行する。

wp_save_post_revision(2024年1月10日 更新)

int | WP_Error | void wp_save_post_revision( int $post_id )
現状の投稿のリビジョンを作成する。

wp_debug_backtrace_summary(2012年6月15日 更新)

mixed wp_debug_backtrace_summary( [ string $ignore_class = null [ , int $skip_frames = 0 [ , bool $pretty = true ] ] ] )
デバッグ用の呼び出し情報を取得する。

nocache_headers(2018年5月27日 更新)

void nocache_headers( )
ブラウザのキャッシュを無効にするHTTPヘッダーを出力する。