ブロックエディターの右上には、設定アイコンの隣にプラグインのアイコンが並ぶことがあります。Yoast SEO などのプラグインが表示している、あの独自パネルです。同じものは registerPlugin と PluginSidebar を使えば自分でも作れます。この記事では、スクリプトを読み込む準備から、サイドバーを表示し、入力した値をカスタムフィールドとして保存するところまでを順に解説します。
目次
registerPlugin で何ができるのか
registerPlugin は @wordpress/plugins パッケージが提供する関数で、ブロックエディターの画面そのものに UI を追加するための入り口です。カスタムブロックを作る registerBlockType が「本文に置ける部品」を増やすのに対して、registerPlugin は「エディターの外枠」を拡張します。
追加できる場所はいくつかあり、目的に応じてコンポーネントを使い分けます。よく使うのは次の3つです。
| コンポーネント | 追加される場所 |
|---|---|
PluginSidebar | 右上のアイコンから開く独立したサイドバー |
PluginSidebarMoreMenuItem | 右上「オプション(︙)」メニューの中の項目 |
PluginDocumentSettingPanel | 「投稿」タブの設定サイドバー内のパネル |
設定項目が2〜3個で済むなら PluginDocumentSettingPanel で投稿設定に混ぜてしまうほうが自然です。項目数が多かったり、チェックリストのように独立した作業画面を持たせたい場合に PluginSidebar を選びます。
なお、これらのコンポーネントは以前 @wordpress/edit-post から読み込むのが定番でしたが、WordPress 6.6 以降は @wordpress/editor からの読み込みが推奨されています。edit-post から読み込むと、投稿画面だけでなくサイト編集画面でも共通して使えないうえ、非推奨の警告が出ます。新規に書くコードでは @wordpress/editor を使ってください。
スクリプトを読み込む準備
registerPlugin はブロックエディター上で動く JavaScript なので、まずはビルドしたスクリプトをエディター画面に読み込ませます。ここでは @wordpress/scripts でビルドする前提で、プラグインとして作る例を示します。
ビルド環境を用意する
プラグイン用のディレクトリを作り、@wordpress/scripts をインストールして build スクリプトを登録します。src/index.js がエントリーポイントになり、build/index.js が出力されます。
{
"name": "my-editor-plugin",
"scripts": {
"start": "wp-scripts start",
"build": "wp-scripts build"
},
"devDependencies": {
"@wordpress/scripts": "^30.0.0"
}
}
npm run build を実行すると build/index.js と一緒に build/index.asset.php が生成されます。この asset ファイルには、コード内で import した WordPress パッケージが依存スクリプトの配列として書き出されています。手で array( 'wp-plugins', 'wp-editor' ) と並べる必要はなく、この配列をそのまま使えば依存関係の書き漏らしを防げます。
enqueue_block_editor_assets で読み込む
読み込みは enqueue_block_editor_assets フックで行います。このフックはブロックエディターの画面でだけ実行されるので、フロントエンドに余計なスクリプトが出る心配はありません。
<?php
/**
* Plugin Name: My Editor Plugin
*/
function myplugin_enqueue_editor_assets() {
// ビルド時に生成される asset ファイルから依存関係とバージョンを読む
$asset = include plugin_dir_path( __FILE__ ) . 'build/index.asset.php';
wp_enqueue_script(
'myplugin-editor',
plugins_url( 'build/index.js', __FILE__ ),
$asset['dependencies'], // wp-plugins や wp-editor が自動で入る
$asset['version'],
true
);
}
add_action( 'enqueue_block_editor_assets', 'myplugin_enqueue_editor_assets' );
テーマの functions.php に書く場合も内容は同じで、パスの取得を get_theme_file_path() と get_theme_file_uri() に置き換えれば動きます。
PluginSidebar でサイドバーを表示する
準備ができたら src/index.js を書きます。registerPlugin の第1引数はプラグインを識別する名前、第2引数はオプションのオブジェクトです。render に渡したコンポーネントがエディターの中でレンダリングされます。
import { registerPlugin } from '@wordpress/plugins';
import { PluginSidebar } from '@wordpress/editor';
import { PanelBody } from '@wordpress/components';
import { megaphone } from '@wordpress/icons';
const MySidebar = () => (
<PluginSidebar
name="my-sidebar" // サイドバーを識別する名前
title="公開前チェック" // アイコンのツールチップと見出しに使われる
icon={ megaphone }
>
<PanelBody title="チェック項目" initialOpen={ true }>
<p>ここに好きな UI を置けます。</p>
</PanelBody>
</PluginSidebar>
);
registerPlugin( 'my-editor-plugin', { render: MySidebar } );
ビルドして投稿編集画面を開くと、右上にメガホンのアイコンが増えているはずです。クリックすると、通常の投稿設定と入れ替わる形で自作のサイドバーが開きます。
registerPlugin の第1引数と PluginSidebar の name は役割が違うので混同しないよう注意してください。前者はプラグイン全体の名前で、小文字の英数字とハイフンだけが使えます。後者は個々のサイドバーの名前で、複数のサイドバーを登録するときの区別や、後述するメニュー項目との紐づけに使われます。
アイコンの指定方法
icon には @wordpress/icons のアイコンのほか、Dashicons の名前を文字列で渡すこともできます。icon="admin-site" のように書けば追加の import は不要です。registerPlugin 側にも icon オプションがありますが、PluginSidebar で指定したものが優先されるので、通常はサイドバー側だけで構いません。
オプションメニューにも項目を出す
アイコンは表示領域が狭いと隠れてしまうことがあります。右上「オプション(︙)」メニューからも開けるようにするには PluginSidebarMoreMenuItem を併記します。target に開きたいサイドバーの name を指定するのがポイントです。
import { registerPlugin } from '@wordpress/plugins';
import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/editor';
import { Fragment } from '@wordpress/element';
import { megaphone } from '@wordpress/icons';
const MySidebar = () => (
<Fragment>
<PluginSidebarMoreMenuItem target="my-sidebar" icon={ megaphone }>
公開前チェック
</PluginSidebarMoreMenuItem>
<PluginSidebar name="my-sidebar" title="公開前チェック" icon={ megaphone }>
<p>ここに好きな UI を置けます。</p>
</PluginSidebar>
</Fragment>
);
registerPlugin( 'my-editor-plugin', { render: MySidebar } );
PluginDocumentSettingPanel で投稿設定に混ぜる
設定が数項目しかないなら、独立したサイドバーより「投稿」タブの中にパネルを足すほうが親切です。読者は普段どおり投稿設定を開くだけで項目にたどり着けます。
import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import { ToggleControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
const MyPanel = () => {
const [ isFeatured, setIsFeatured ] = useState( false );
return (
<PluginDocumentSettingPanel
name="my-document-panel" // パネルの識別名
title="記事の設定" // パネルの見出し
className="my-document-panel"
>
<ToggleControl
__nextHasNoMarginBottom
label="トップページで大きく表示する"
checked={ isFeatured }
onChange={ ( value ) => setIsFeatured( value ) }
/>
</PluginDocumentSettingPanel>
);
};
registerPlugin( 'my-document-panel', { render: MyPanel } );
この状態ではトグルを切り替えても値はどこにも保存されません。次の節で、入力した内容をカスタムフィールドとして保存できるようにします。
入力した値をカスタムフィールドに保存する
ブロックエディターから投稿メタ(カスタムフィールド)を読み書きするには、PHP 側でメタキーを登録し、JavaScript 側で useEntityProp を使うという2段構えになります。
register_post_meta でメタキーを登録する
エディターは REST API 経由で投稿を保存するため、show_in_rest が true のメタキーしか扱えません。single を true にすると値が配列ではなく単一の値として返ります。
function myplugin_register_meta() {
register_post_meta(
'post', // 対象の投稿タイプ
'myplugin_is_featured',
array(
'type' => 'boolean',
'single' => true,
'default' => false,
'show_in_rest' => true, // これがないとエディターから読み書きできない
'auth_callback' => function () {
return current_user_can( 'edit_posts' );
},
)
);
}
add_action( 'init', 'myplugin_register_meta' );
useEntityProp で読み書きする
@wordpress/core-data の useEntityProp は、編集中の投稿のプロパティを React の state のように扱えるフックです。meta を指定すると、投稿メタ全体のオブジェクトと、その更新用の関数が返ります。
import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel, store as editorStore } from '@wordpress/editor';
import { ToggleControl } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useEntityProp } from '@wordpress/core-data';
const MyPanel = () => {
// 編集中の投稿タイプを取得する
const postType = useSelect(
( select ) => select( editorStore ).getCurrentPostType(),
[]
);
// meta オブジェクトと更新関数を受け取る
const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
const isFeatured = meta?.myplugin_is_featured ?? false;
return (
<PluginDocumentSettingPanel name="my-document-panel" title="記事の設定">
<ToggleControl
__nextHasNoMarginBottom
label="トップページで大きく表示する"
checked={ isFeatured }
onChange={ ( value ) =>
// 既存の meta を残したまま該当キーだけ上書きする
setMeta( { ...meta, myplugin_is_featured: value } )
}
/>
</PluginDocumentSettingPanel>
);
};
registerPlugin( 'my-document-panel', { render: MyPanel } );
setMeta にはオブジェクト全体を渡す必要があるため、スプレッド構文で既存の値を展開してから対象のキーを上書きします。ここで setMeta( { myplugin_is_featured: value } ) と書いてしまうと、他のプラグインが使っているメタまで巻き添えで消えかねません。
値を変更するとエディターが「未保存の変更あり」の状態になり、更新ボタンを押したタイミングで投稿本体と一緒に保存されます。保存用の処理を自分で書く必要はありません。フロントエンドでは get_post_meta( get_the_ID(), 'myplugin_is_featured', true ) で読み出せます。
サイドバーが表示されないときの確認点
アイコンが増えない、パネルが出てこないという場合、原因はだいたい次のどれかです。ブラウザーの開発者ツールでコンソールを開き、エラーが出ていないかを合わせて確認してください。
依存スクリプトが足りていない
コンソールに wp.plugins is undefined のようなエラーが出ている場合、wp_enqueue_script() の依存配列に wp-plugins や wp-editor が入っていません。自作の配列を書かず、build/index.asset.php の dependencies をそのまま渡すのが確実です。ビルドせずに src/index.js を直接読み込もうとしている場合も、JSX や import 文がブラウザーで解釈できずここで止まります。
プラグイン名の書式が正しくない
registerPlugin の第1引数に使えるのは小文字の英数字とハイフンだけで、先頭を数字やハイフンにすることもできません。myPlugin や my_plugin のように書くと登録が拒否され、コンソールに警告が出た状態で何も表示されなくなります。
非推奨のパッケージから読み込んでいる
古い記事を参考にして @wordpress/edit-post から PluginDocumentSettingPanel を import していると、環境によっては undefined になり、コンポーネントとして描画しようとした時点でエラーになります。読み込み元を @wordpress/editor に変更してください。
トグルの値が保存されない
UI は表示されるのに値が戻ってしまう場合は、register_post_meta() の show_in_rest が true になっているか、登録した投稿タイプが編集中のものと一致しているかを確認します。カスタム投稿タイプでメタを使うときは、その投稿タイプ自体が show_in_rest に対応している必要もあります。type の指定と実際に渡している値の型が食い違っている場合(boolean なのに文字列を渡すなど)も、REST API 側で弾かれて保存されません。
まとめ
registerPlugin は、ブロックエディターの画面そのものに UI を足すための関数です。独立した作業領域が欲しいときは PluginSidebar、設定を数項目足したいだけなら PluginDocumentSettingPanel を選ぶと、読者にとって自然な場所に収まります。値を保存したい場合は register_post_meta() でメタキーを登録し、useEntityProp で読み書きすれば、投稿の更新と同時に保存されます。コンポーネントの読み込み元は @wordpress/edit-post ではなく @wordpress/editor にしておきましょう。