メタボックス

概要

ブロックエディター以前は、エディターの拡張にカスタムメタボックスが使用されていました。現在は新しい拡張方法があり、開発者にさらなるパワーを与え、ユーザーにより良い体験を与えます。古いカスタムメタボックスは、新しい方法の一つに移植することが推奨されています。エディターの利用者に、統一され一貫性のあるユーザー体験を作ることができます。

ブロックエディターは、ほとんどの既存のメタボックスをサポートします。詳細については、後方互換性に関する記事を参照してください。

エディターの外部で投稿メタを操作したい場合は、サイドバーチュートリアルを参照してください。

Top ↑

ブロックを使用したメタ情報の保存

一般にブロックは属性の値をシリアライズしたブロックの HTML 内に保存します。しかし属性の値を投稿メタとして保存するブロックを作成することもできます。こうするとテンプレートの任意の場所からプログラム的に属性へアクセスできます。

このガイドは、ユーザーに値の入力を求め、その値を投稿メタに保存するブロックを作成する方法を紹介します。

Top ↑

はじめる前に

このガイドでは、すでに WordPressのプラグイン、投稿メタ、基本的な JavaScript に親しんでいることを前提としています。入門としては、JavaScript 入門 チュートリアル を参照してください。

このガイドでは、基本的なブロックの作成方法を説明します。しかし、カスタムブロックの作成をより深く理解するには、ブロック作成チュートリアルの参照を推奨します。

以下が必要です。

  • WordPress 開発環境
  • 最小のプラグインの有効化と、編集可能なセットアップ
  • JavaScript のビルドとエンキューが可能なセットアップ

完全なメタブロックのサンプル が利用可能です。セットアップの参考にしてください。

Top ↑

ステップバイステップガイド

  1. メタフィールドの登録
  2. メタブロックの追加
  3. 投稿メタデータの使用
  4. 最後の仕上げ

Top ↑

ステップ 1: メタフィールドの登録

投稿メタフィールドは、投稿の追加データの保存に使用される WordPress オブジェクトです。使用前にまず新しいメタフィールドを登録する必要があります。投稿メタの詳細については投稿メタデータの管理を参照してください。

フィールドの登録の際には show_in_rest パラメータに注意してください。このパラメータによりデータが REST API に含まれます。ブロックエディターは REST API を使用してメタデータをロードしたり保存します。詳細な情報については register_post_meta 関数定義を参照してください。

また register_post_meta 関数が動作するには投稿タイプが custom-fields をサポートする必要があります。

フィールドを登録するには、次のコードを PHP プラグインに追加してください。

<?php
// カスタムメタタグフィールドを登録する。
function myguten_register_post_meta() {
	register_post_meta( 'post', 'myguten_meta_block_field', array(
		'show_in_rest' => true,
		'single' => true,
		'type' => 'string',
	) );
}
add_action( 'init', 'myguten_register_post_meta' );

Top ↑

ステップ 2: メタブロックの追加

次に、前のステップで登録したメタフィールドを使用して、ユーザーにフィールド値を表示する新しいブロックを作成します。

メタの値を取得したり変更するにはブロックからフック useEntityProp を使用します。

このコードを JavaScript src/index.js に追加してください。

import { registerBlockType } from '@wordpress/blocks';
import { TextControl } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useEntityProp } from '@wordpress/core-data';
import { useBlockProps } from '@wordpress/block-editor';

registerBlockType( 'myguten/meta-block', {
	edit: ( { setAttributes, attributes } ) => {
		const blockProps = useBlockProps();
		const postType = useSelect(
			( select ) => select( 'core/editor' ).getCurrentPostType(),
			[]
		);

		const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );

		const metaFieldValue = meta[ 'myguten_meta_block_field' ];
		const updateMetaValue = ( newValue ) => {
			setMeta( { ...meta, myguten_meta_block_field: newValue } );
		};

		return (
			<div { ...blockProps }>
				<TextControl
					label="Meta Block Field"
					value={ metaFieldValue }
					onChange={ updateMetaValue }
				/>
			</div>
		);
	},

	// ブロックに情報は保存されない。
	// データは、フックを介して、投稿メタに保存される。
	save: () => {
		return null;
	},
} );

動作を確認するには、投稿を作成し、メタブロックを追加してください。値を入力できるフィールドが表示されます。下書きまたは公開で、投稿を保存すると、投稿のメタ値も保存されます。下書きを保存し、再読み込みすると、フォームが入力されたままになることで検証できます。

また、データの保存を確認する別の方法として、データベーステーブル wp_postmeta をチェックして、新しい投稿 ID が新しいフィールドデータを含んでいることを確認してください。

トラブルシューティング: 変更の合間に忘れずにコードをビルドしてください。ステップ 1から PHP コードを更新し、JavaScript ファイルをエンキューしています。ビルドの出力と開発者コンソールのエラーを確認してください。

Top ↑

ステップ 3: 投稿メタデータの使用

前のステップで保存した投稿メタデータはいくつかの方法で使用できます。

Top ↑

PHP での投稿メタの使用

最初の例では投稿メタフィールドからの値を H4 タグで囲んで、投稿コンテンツの最後に追加します。

function myguten_content_filter( $content ) {
	$value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true );
	if ( $value ) {
		return sprintf( "%s <h4> %s </h4>", $content, esc_html( $value ) );
	} else {
		return $content;
	}
}
add_filter( 'the_content', 'myguten_content_filter' );

Top ↑

ブロックでの投稿メタデータの使用

投稿メタデータは、別のブロックでも使えます。この例では、レンダーの際にすべての「段落」ブロックの末尾にデータがロードされます。すなわち、ユーザーに表示されます。必要であれば、段落ブロックは、任意のコアブロックやカスタムブロックタイプで置き換えられます。

PHP では register_block_type 関数を使用してコールバックを設定し、ブロックをレンダーする際にメタ値を含めます。

function myguten_render_paragraph( $block_attributes, $content ) {
	$value = get_post_meta( get_the_ID(), 'myguten_meta_block_field', true );
	// 出力前に値がセットされているかをチェックする。
	if ( $value ) {
		return sprintf( "%s (%s)", $content, esc_html( $value ) );
	} else {
		return $content;
	}
}

register_block_type( 'core/paragraph', array(
	'api_version' => 2,
	'render_callback' => 'myguten_render_paragraph',
) );

Top ↑

ステップ 4: ブロックテンプレートの使用 (オプション)

メタブロックを使う際の1つの問題点は、ユーザーが投稿ごとにブロックを追加する必要があり、これを簡単に忘れてしまう点にあります。この問題を解決するには、ブロックテンプレートを使用します。ブロックテンプレートは投稿タイプごとに事前定義された、ブロック要素のリストです。テンプレートを使用することで投稿タイプのデフォルトの初期状態を指定できます。

この例では、テンプレートを使用して、自動的に投稿の先頭にメタブロックを挿入します。

次のコードを myguten-meta-block.php ファイルに追加してください。

function myguten_register_template() {
    $post_type_object = get_post_type_object( 'post' );
    $post_type_object->template = array(
        array( 'myguten/meta-block' ),
    );
}
add_action( 'init', 'myguten_register_template' );

配列には他のブロックタイプも追加できます。プレースホルダーを設定したり、投稿を特定のブロックの集合にロックできます。テンプレートは編集体験を制御する強力なツールです。詳細については上のリンク先のドキュメントを参照してください。

Top ↑

まとめ

このガイドでは、ブロックを使って投稿メタの読み書きを行う方法を紹介しました。既存のメタボックスとの後方互換性については、以下のセクションを参照してください。

Top ↑

後方互換性

Top ↑

既存のメタボックスのテスト、変換、メンテナンス

実際にメタボックスをブロックに変換する前に、まず、メタボックスがブロックエディターで動作するかどうかをテストし、動作の有無を明示的にマークするほうが簡単でしょう。

メタボックスがブロックエディターで動作せず、正しく動作するように更新することもできない場合は、次のステップとしてメタボックスの宣言に __block_editor_compatible_meta_box 引数を追加します。

add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback',
	null, 'normal', 'high',
	array(
		'__block_editor_compatible_meta_box' => false,
	)
);

WordPress はメタボックスを表示しませんが、ブロックエディタと互換性がない旨のメッセージと、Classic Editorプラグインへのリンクを表示します。デフォルトでは __block_editor_compatible_meta_box は true です。

メタボックスをブロックに変換できた場合、後方互換性のために以下のように宣言できます。

add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback',
	null, 'normal', 'high',
	array(
		'__back_compat_meta_box' => true,
	)
);

このメタボックスは後方互換性のためにのみ存在するため、ブロックエディターではメタボックス領域に表示されません。クラシックエディターでは、従来どおり表示されます。

Top ↑

メタボックスデータコレクション

ブロックエディターのページロードごとに、メタボックスのデータを収集し、領域が空かどうかを判断するアクションを登録します。メタボックスのデータを収集すると、元のグローバル state はリセットされます。

register_and_do_post_meta_boxes を参照してください。

内部では、post.php がメタボックスの登録に実行する関数とフック、具体的には、add_meta_boxesadd_meta_boxes_{$post->post_type}do_meta_boxes が実行されます。

メタボックスはフィルタリングされ、コアのメタボックス、標準カスタムタクソノミーのメタボックス、後方互換性のためにのみ存在すると宣言したメタボックスが除去されます。

次に、この特定のタイプのメタボックスのそれぞれの位置がアクティブかどうかがチェックされます。空でない場合は true が格納され、空の場合は false が格納されます。このメタボックスの位置データは、エディターの Redux ストアから INITIALIZE_META_BOX_STATE にディスパッチされます。

理想的には、この処理をエディターのインスタンス化時に行うことで、フローを簡素化できます。しかし、initializeEditor() 呼び出し時の、 admin_enqueue_scripts より前に、メタボックスの状態を知ることはできません。フッターや admin_head より後に initializeEditor() を実行しない限り、現在の方法で対応するしかありません。ただし、最近のエディターのブートストラップに関する変更で、可能になったかもしれません。念のため、ACFでテストしてみてください。

Top ↑

Redux と React のメタボックス管理

ブロックエディターをレンダリングする際、メタボックスは hidden div #metaboxes にレンダーされます。

Redux store は、デフォルトですべてのメタボックスを非アクティブとして保持します。このとき INITIALIZE_META_BOX_STATE が来ると、store は、任意のアクティブなメタボックス領域を更新し、isActive フラグを true にセットします。これが起きると、React は、MetaBox コンポーネントの Redux から送られた、新しい props をチェックします。その MetaBox がアクティブなら、null をレンダリングする代わりに、MetaBoxArea コンポーネントがレンダーされます。MetaBox コンポーネントはコンテナコンポーネントで、 MetaBoxArea と Redux Sotre の間を仲立ちします。アクティブなメタボックスがなければ、何も起きません。すべてのコアのメタボックスは除外されているため、これがデフォルトの動作です。

Top ↑

MetaBoxArea コンポーネント

コンポーネントはレンダーすると、メタボックスコンテナへの参照を保存し、プリフェッチした場所からメタボックス HTML を取得します。

投稿が更新されると、アクティブなメタボックス領域のみが送信されます。これにより、不要なリクエストの送信を防ぎます。メタボックスが送信されても、余分なリビジョンは作成されません。任意のアクティブなメタボックスの REQUEST_POST_UPDATE で Redux アクションがトリガーされます。editor/effects.js を参照してください。REQUEST_META_BOX_UPDATESアクションは、メタボックスの state をisUpdatingに設定します。isUpdating prop は MetaBoxArea に送られ、フォームの送信を起こします。

メタボックス領域の保存中は、更新中のオーバーレイを表示し、保存中にユーザーがフォームの値を変更できないようにします。

以下に、保存用 URL の例を挙げます。

mysite.com/wp-admin/post.php?post=1&action=edit&meta-box-loader=1

この URL は、グローバル変数 _wpMetaBoxUrl を介して、自動的に React に渡されます。

このページは post.php の投稿フォームを真似ており、送信されると通常のフックとアクションをすべて起動し、既存のコードを変更しなくても、任意の PHP メタボックスのあれこれを正しく起動する、適切なグローバル state を持ちます。送信が成功すると、React は handleMetaBoxReload をシグナルして、更新中のオーバーレイを削除します。

Top ↑

一般的な互換性の問題

ほとんどの PHP メタボックスはブロックエディタでも引き続き動作するはずです。しかし、高度な機能を含む一部のメタボックスは壊れる可能性があります。以下は、ブロックエディタでメタボックスが期待どおりに動作しない一般的な理由です。

  • 投稿タイトル、投稿コンテンツフィールド、その他の旧エディタのメタボックスを対象とするセレクタに依存するプラグイン
  • TinyMCE の API に依存するプラグイン。ブロックエディタ内には対話する単一の TinyMCE インスタンスがない。
  • 「公開」や「保存」の DOM を更新するプラグイン

また、プラグインが PHP の警告や通知をページ上に出力しないかを注意してください。HTML ドキュメントタイプ(<!DOCTYPE html>)が正しく出力されません。結果、ブラウザは「Quirks Mode」を使用してレンダーします。これはブラウザがパースしているドキュメントのタイプが分からない場合に有効化される互換性レイヤーです。ブロックエディターは、このモードでは動作しませんが、正常に動作しているように見える場合があります。メタボックスがエディターと重なったり、その他のレイアウトの問題が発生した場合、ドキュメントの生のページソースをチェックして、ページの最初にドキュメントタイプの定義が出力されていることを確認してください。また、JavaScript コンソールには、問題を示す警告が表示されます。

原文

最終更新日: