WordPressでカスタムフィールドの操作を編集画面下にあるカスタムフィールド一覧で直接書き換えずに、どこかのパネルで変更させたいという時に使うメタボックス、このページに到達した方は当然これを使ったコードの書き方はご存じでしょう。
でもWordPress 7.0で加わるリアルタイムコラボレーション(共同編集機能)では、メタボックスへの値の変更は基本的にsave_postにフックさせる、つまり「更新」などのボタンをクリックしないと動作しないので、データに不整合が起こる可能性があることから、メタボックスが1つでも存在する編集画面では、設定でリアルタイムコラボレーションを有効にしても機能しないようになっています(他の人が参加しようとすると無理やり編集権限を取り上げるか立ち去るかのいずれかの選択になります)。
これでは使うかどうかは別の話として、せっかくの新機能が使えないようになってしまいます。
そこで考えられるのが、先日公開した「リアルタイムコラボレーション有効化時のメタボックスの扱い方(例)」で書いているように、リアルタイムコラボレーションが有効の場合にはメタボックスを表示しないという方法なのですが、できればそうした制限なく全機能を使えるようにしておきたいものですね。
そこでおすすめなのがメタボックスではなくWordPress標準の「カテゴリー」や「タグ」の設定と同じ仕組みのパネルを用意してREST APIを使って更新する方法。
これを実装する方法を検索したりAIに聞いたりして出てくるのが開発環境用意して、または開発環境ありきのページや回答、私のように開発環境を持たない人にとってはハードルが高いどころかスタートラインにも立てない状況になってあきらめるしかなくなってしまいます。
そこで今回は、脱メタボックス、リアルタイムコラボレーションが問題なく使えるようにする方法を、開発環境なしでも実装できるサンプルコードをいくつか用意して紹介したいと思います。
検索で参考ページをいくつも見ながら、AIに手伝ってもらいながらで結構時間をかけて苦労して完成したものなので私だけの秘密にするつもりでしたが、同じように困っている誰かの一助になれば幸いです..。
本ページでは旧来のカスタムフィールド値設定窓をメタボックス(これはWordPress公式の呼称)、今回紹介するREST API経由でのカスタムフィールド値設定窓をメタパネル(これは私が勝手に命名)と呼ぶことにしますので以後読み替えてください
コードサンプル含めかなりの長文になりますので、ブックマークなどしてじっくりとお読みください
なお、長年WordPressでのカスタマイズを行っているものの、私自身JS、今回のようなメタパネル追加や独自ブロックを追加するなどといった、特にブロックエディターに何かの変更を加えるものについては初心者に近いです。本ページはそんな私でもAIの力を借りてメタパネルの実装ができ、こうして解説記事として公開することで自身の理解の深耕も兼ねていることを予めお断りしておきます。
コードを使用する前に、ここをクリックして注意事項をご確認ください
本ページで掲載しているコードは、以下に了承した上で使用ください
- コードは商用・非商用問わず自由に使っていただいて構いませんが、コード追加による不具合やトラブルが発生しても当方では一切責任を負いません
- コードは有効化しているテーマのfunctions.php、style.cssなどへ追加することで機能します。それらのファイルへの変更を行うことに不安のある方は使用しないでください
- コードは本ページの公開日時点で私の環境において動作したものです。WordPressバージョン他環境の違いによって動作しないことがあります
- コードは、セキュリティ、コードの正確さなどにおいて完全なものではありません。中には紹介するコードを簡略化するために省略している部分があるものもありますので、ご自身でコードを十分に検証し、必要な部分の編集を行った上で使用するようにしてください
- 掲載しているのは参考コードです。自身の環境に合わせるための編集はご自身で対応いただく必要があります(コメント欄等から質問いただいても基本回答は致しません)
- 掲載しているコードの転載を禁じます(SNSで紹介いただいたり、本ページへのリンクを張っていただくことは大歓迎です)
標準のカスタムフィールド一覧を無効にする【必須の前準備】
本ページのサンプルコードを使ってメタパネルが追加され、入力された値がきちんと更新されているかを、標準のカスタムフィールド一覧で確認するというのは、メタボックス時代ではよくあるケースですね。
でも、今回のカスタムパネルを使用する方法の場合はREST APIを使用するため、カスタムフィールド一覧が編集画面内に存在している状態だと、「REST API使って値を書き換えようとしたけど、旧来のカスタムフィールドの入力欄(一覧)があるからそちらが優先だな」と判断して、メタパネル内に入力した値が更新されないという現象が発生します。
これは、例えば本ページで紹介するサンプルコードのまま(つまり今まで一度も使われていないカスタムフィールド名)の場合には、存在しないので最初に設定・入力した値は保存されますが、値を変えて更新する際には最初の設定値に戻ってしまうという、一見不具合や動作しないコードなのでは?と感じる挙動になります。
実はこの現象が発生するのがまさか「カスタムフィールド一覧」を表示しているからだと思わず結構な時間いろいろなデバッグを行った結果、実装不能と一時判断した時間もありましたので、私と同じ現象に徒労しないよう、以下のコードを使って「カスタムフィールド一覧」を無効にし、ブロックエディターの「設定」メニューでも「カスタムフィールド」の有効/無効スイッチが出ないようにする措置をしておきましょう。
※簡易な処理なので無名関数のままにしていますが、ユーザー定義関数化したい方はご自身で変換してください
add_action( 'init', function() {
remove_post_type_support( 'post', 'custom-fields' );
} );
メタパネルを実装するサンプルコード
必ず前項の「標準のカスタムフィールド一覧を無効にする」を確実に行ってから先に進んでください
前準備
どんなサイトでも構いませんし、有効化しているテーマはブロックテーマ・クラシックテーマに関わらずブロックエディターが正常に動作すれば何でも構いませんが、きちんと動作するのかを確認しやすくするため、できればテスト用サイトを用意して、Twenty Twenty-FiveなどWordPressのデフォルトテーマとして採用されていて、かつ、functions.phpが標準で存在するテーマを使ってテストすることをおすすめします。
また、最終的にリアルタイムコラボレーションが利用できることの確認、メタパネルでの値変更が共同編集者すべての編集画面で即座に反映されるかも確認いただきたいので、既存のサイトでテストされる場合は、メタボックスを表示する機能をコードで追加している場合は停止し、投稿編集画面に何等かのメタボックスを出力するプラグインは停止していただくと、スムーズに実装まで進められると思います。
ブロックエディターによる投稿の編集ができているサイトであれば問題ないかとは思いますが、メタパネルはREST APIを使ってデータの更新を行うものですので、REST APIに対して何かの制限を行うコードやプラグインがある場合は一応そちらも停止してください
メタパネルを追加して機能するようにするには、functions.phpに書くPHPコードと、実際にパネルを表示させて動作をさせるJavaScriptが必要となります。
「pwcn-metapanel.js」というファイルをテーマフォルダ直下に追加して以下のコードをfunctions.phpへ追加しておいてください。
function pwcn_meta_panel_js_init(){
wp_enqueue_script(
'pwcn-meta-panel-js',
get_template_directory_uri() . '/pwcn-metapanel.js',
[ 'wp-plugins', 'wp-edit-post', 'wp-element', 'wp-components', 'wp-data', 'wp-i18n' ],
filemtime( get_template_directory() . '/pwcn-metapanel.js' )
);
}
add_action('enqueue_block_editor_assets','pwcn_meta_panel_js_init');
文字列を保存させるためのメタパネルのサンプルコード
まずはメタパネルを作ってテキスト入力窓を表示させ、そこに入力した文字列がカスタムフィールド値として保存されるようにするサンプルコードを紹介します。その後それを基本として詳しく説明をさせていただき、「テキストエリア(長文用)」「チェックボックス」「ラジオボタン」「セレクトボックス」「カスタムフィールドの操作を行わない説明欄」のサンプルコードを紹介しますので、どこがどう違うのかを見比べて実装に役立ててください。
functions.phpへのコード追加
/*** テキストのサンプル ***/
add_action( 'init', function() {
// 対象にしたい投稿タイプを配列で指定
$post_types = ['post'];
//メタキーを指定
$meta_key = 'my_custom_text';
foreach ( $post_types as $post_type ) {
register_post_meta(
$post_type,
$meta_key,
[
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
]
);
}
} );
※無名関数にしていますので、ユーザー定義関数を使いたい方はご自身で書き換えてください
pwcn-metapanel.jsへのコード追加
以下のコードを「pwcn-metapanel.js」へ追加してください。
//テキストボックスの場合のJS
(function (wp) {
/*** 必要な関数やツールの準備 ***/
// Reactの要素を作成するための関数(PHPのHTML出力に相当する役割)
var el = wp.element.createElement;
// 作成したパネルをWordPressのエディターに正式に登録するための関数
var registerPlugin = wp.plugins.registerPlugin;
// 投稿設定サイドバー(右側の「投稿」タブ)の中に新しいパネル(アコーディオン)を作るための部品
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
// データベース(メタデータ)から現在の値を取得するための「読み込み」用ツール
var useSelect = wp.data.useSelect;
// 入力された値をデータベースへ反映( dispatch )するための「書き込み」用ツール
var useDispatch = wp.data.useDispatch;
// 1行のテキスト入力欄を表示する
var TextControl = wp.components.TextControl;
/*** メタパネルの定義 ***/
var MyCustomPanel = function () { //MyCustomPanelという名前の領域にパネルを追加する
// 1. 現在のメタデータを取得
var meta = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute('meta') || {};
}, []);
// 2.メタキーが定義されていない投稿タイプならフォームを非表示にする
// register_post_metaの第二引数で指定したメタキーを指定
if (meta['my_custom_text'] === undefined) {
return null;
}
// 3. 更新用関数を取得
var { editPost } = useDispatch('core/editor');
return el(
PluginDocumentSettingPanel,
{
//パネルの名前、文字列、アイコンを指定
//nameはサイト内で一意である必要がある点に注意
name: 'my-custom-panel',
title: 'テキストパネル',
icon: 'admin-generic',
},
//TextControl(文字列)として処理
el(TextControl, {
//入力欄の上に表示する説明
label: '文字列',
//register_post_metaの第二引数で指定したメタキーの値を表示
value: meta['my_custom_text'] || '',
__next40pxDefaultSize: true,
onChange: function (newValue) {
// 3. メタデータの特定キーだけを上書きして送信
editPost({
meta: {
//register_post_metaの第二引数で指定したメタキーを指定
'my_custom_text': newValue
}
});
}
})
);
};
//MyCustomPanelという領域にmy-custom-panel-pluginという名前のパネルを出力する
//領域やパネル名は一意である必要がある点に注意
registerPlugin('my-custom-panel-plugin', { render: MyCustomPanel });
})(window.wp);
動作テスト
コードを紐解く前に、とにかく動作するかを見てみたいと思いますので、早速確認してみましょう。
投稿編集画面(既存の投稿でも、新規投稿でもOK)を開き、右サイドパネルにある「投稿」タブ(アイキャッチ画像などがあるパネルの集まり)を表示させて、下へスクロールしていくと、下図左のように「テキストパネル」というのが表示されているはずです。
そして「テキストパネル」をクリックすると、下図右のように「文字列」というタイトルの入力窓が表示されているはずです。


さらに入力窓に何か文字列を入力してみてください。入力した段階でカスタムフィールドの値をこの値にする準備が整い、「下書き保存」「公開」「更新」などをクリックすることで確定されるという流れで値が確実に書き換わるはずです。
入力値を変更した段階では準備ができているだけで実際の書き換えはされないため、保存ボタンをクリックしないで編集画面をリロードしたり編集画面から移動しようとすると以下のような警告が表示され、そのまま閉じると変更値は保存されない点に注意してください
ここまで来たらひとまずメタボックスを使わずにカスタムフィールドの値を更新する機構が完成しました。ついでにメタパネルにする最大の目的であるリアルタイムコラボレーションの動作確認をしておきましょう。
リアルタイムコラボレーションの確認
リアルタイムコラボレーション(共同編集)機能はWordPress7.0から利用できる機能ですので、7.x正式リリース前であればWordPress Beta Testerを使って7.0RCなどのバージョンにしてください。
WordPress 7.x以降になっていれば、管理画面の「設定」→「投稿設定」を開くと「共同編集」というチェック欄があるので有効化して設定を保存します。
次に共同編集のテストを行うユーザーが必要ですので、ユーザーの新規作成(投稿者権限以上)を行ってください。
下書き済でも公開済みでもいいので、投稿の編集画面を開きます(新規作成の場合は何かのブロックを追加して下書き保存してください)。※この画面は開いたままにしてください。
別のブラウザ、またはシークレットウインドウを開いて同じサイトのログイン画面を開き、先ほど作成したユーザーでログインし、投稿一覧画面を開き、(編集中)となっている投稿の「参加」をクリックして編集画面を開いてください。
投稿編集画面に何の警告画面も表示されなければこの段階で共同編集ができる状態になっています。もしも「引き継ぐ」「キャンセル」などというボタンと警告文が表示される場合は、手順に誤りがあるか、メタボックスが含まれる投稿を開いていることが原因なので諸所確認ください。
双方の編集画面で、ブロックを追加・編集したりして、リアルタイムに編集画面の内容が変わるかを確認します(結構感動します)。その後、メタパネルに入力した文字を変更してみて、別ユーザーの編集画面でもその値がリアルタイムに書き換わるかを確認してください(こちらも結構感動します)。
ちなみにページ冒頭などでちらっと触れましたがメタボックスが1つでも存在している投稿の編集画面ではリアルタイムコラボレーション(共同編集)は無効になります(そもそもこの問題を解決したくて本ページをご覧になっているはずです)。
コードの簡易解説とまとめ
以下がメタパネルを動作させるための大まかな流れです。
- メタパネルを動作させるためのjsファイルを読み込ませる(前準備)
- カスタムフィールドの定義を登録する(functions.phpへのコード追加)
- メタパネルの表示・値の更新をするJSコードを追加(pwcn-metapanel.jsへのコード追加)
以下がJSコードの大まかな流れです。私のようにJSに明るくない人でなくても分かるよう、前述のJSコードにはたくさんコメントを入れていますので見比べながら確認してみてください。
- WordPress本体からいろいろな定義や動作を行うプログラムを起動させるための記述
- どの領域にメタパネルを追加するのかで囲む
- 領域内のメタパネル内で操作するカスタムフィールドのキーとパネル内の文字列、値の引き出しと更新
- メタパネルの内容でブロックエディターへパネルを展開する
つまりPHP側ではカスタムフィールドキーの登録をして、REST APIを使って値の引き出しと更新をしますよ!としているだけで、あとはJS側が処理するということなんですね。
前述のコードで動作が確認できたら、タイトルやフォーム上の文字を変更したり、領域名を変更したりしてどのように変化するのか、どことどこを共通にしたりどこにキーを入れたりすればいいのかなどを試した後、例えば同じ流れのものを追加して編集して複数の文字列メタパネルを操作できるようにしてみるなど、コード体系と編集点を確認しつつ遊んでみてください。
指定した投稿タイプだけにパネルを表示させたいときは
前述のJSコード側で投稿タイプを限定するコードを追加します(追加する部分は「ここを追加」とコメントしてます)
//テキストボックスの場合のJS
(function (wp) {
/*** 必要な関数やツールの準備 ***/
// Reactの要素を作成するための関数(PHPのHTML出力に相当する役割)
var el = wp.element.createElement;
// 作成したパネルをWordPressのエディターに正式に登録するための関数
var registerPlugin = wp.plugins.registerPlugin;
// 投稿設定サイドバー(右側の「投稿」タブ)の中に新しいパネル(アコーディオン)を作るための部品
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
// データベース(メタデータ)から現在の値を取得するための「読み込み」用ツール
var useSelect = wp.data.useSelect;
// 入力された値をデータベースへ反映( dispatch )するための「書き込み」用ツール
var useDispatch = wp.data.useDispatch;
// 1行のテキスト入力欄を表示する
var TextControl = wp.components.TextControl;
/*** ここを追加 ***/
var useSelect = wp.data.useSelect; // 投稿タイプ取得
/*** メタパネルの定義 ***/
var MyCustomPanel = function () { //MyCustomPanelという名前の領域にパネルを追加する
/*** ここを追加 ***/
//指定した投稿タイプで出力
//現在の投稿タイプを取得
var postType = useSelect(function (select) {
return select('core/editor').getCurrentPostType();
}, []);
// 表示を許可する投稿タイプのリスト(配列)
var allowedPostTypes = ['post','page']; // 投稿タイプを配列指定
// リストに含まれていない場合は表示しない
if (!allowedPostTypes.includes(postType)) {
return null;
}
/*** ここまで追加 ***/
// 1. 現在のメタデータを取得
var meta = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute('meta') || {};
}, []);
// 2.メタキーが定義されていない投稿タイプならフォームを非表示にする
// register_post_metaの第二引数で指定したメタキーを指定
if (meta['my_custom_text'] === undefined) {
return null;
}
// 3. 更新用関数を取得
var { editPost } = useDispatch('core/editor');
return el(
PluginDocumentSettingPanel,
{
//パネルの名前、文字列、アイコンを指定
//nameはサイト内で一意である必要がある点に注意
name: 'my-custom-panel',
title: 'テキストパネル',
icon: 'admin-generic',
},
//TextControl(文字列)として処理
el(TextControl, {
//入力欄の上に表示する説明
label: '文字列',
//register_post_metaの第二引数で指定したメタキーの値を表示
value: meta['my_custom_text'] || '',
__next40pxDefaultSize: true,
onChange: function (newValue) {
// 3. メタデータの特定キーだけを上書きして送信
editPost({
meta: {
//register_post_metaの第二引数で指定したメタキーを指定
'my_custom_text': newValue
}
});
}
})
);
};
//MyCustomPanelという領域にmy-custom-panel-pluginという名前のパネルを出力する
//領域やパネル名は一意である必要がある点に注意
registerPlugin('my-custom-panel-plugin', { render: MyCustomPanel });
})(window.wp);
文字列をPHPから渡したいときは
これまではJS内に文字列をべた書きしたものを紹介しましたが、wp_localize_script()関数を使って文字列を渡すこともできます。前述のサンプルコードを元にPHP、JS共に以下のようにします。
/*** テキストのサンプル ***/
add_action( 'init', function() {
// 対象にしたい投稿タイプを配列で指定
$post_types = ['post'];
//メタキーを指定
$meta_key = 'my_custom_text';
foreach ( $post_types as $post_type ) {
register_post_meta(
$post_type,
$meta_key,
[
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
]
);
//スクリプトに渡すための文字列と翻訳可能文字列を紐づけて配列にする
$localize_val = array(
'title' => __('テキストパネル','text-domain'),
'label' => __('文字列','text-domain'),
);
//wp_localize_scriptを使ってスクリプトへ配列を渡す
wp_localize_script( $script_name , 'PwcnLocalizeText', $localize_val);
}
} );
//テキストボックスの場合のJS
(function (wp) {
/*** 必要な関数やツールの準備 ***/
// Reactの要素を作成するための関数(PHPのHTML出力に相当する役割)
var el = wp.element.createElement;
// 作成したパネルをWordPressのエディターに正式に登録するための関数
var registerPlugin = wp.plugins.registerPlugin;
// 投稿設定サイドバー(右側の「投稿」タブ)の中に新しいパネル(アコーディオン)を作るための部品
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
// データベース(メタデータ)から現在の値を取得するための「読み込み」用ツール
var useSelect = wp.data.useSelect;
// 入力された値をデータベースへ反映( dispatch )するための「書き込み」用ツール
var useDispatch = wp.data.useDispatch;
// 1行のテキスト入力欄を表示する
var TextControl = wp.components.TextControl;
//文字列(PHPのwp_localize_script()で渡した変数を受け取る)
const T = PwcnLocalizeText;
/*** メタパネルの定義 ***/
var MyCustomPanel = function () { //MyCustomPanelという名前の領域にパネルを追加する
// 1. 現在のメタデータを取得
var meta = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute('meta') || {};
}, []);
// 2.メタキーが定義されていない投稿タイプならフォームを非表示にする
// register_post_metaの第二引数で指定したメタキーを指定
if (meta['my_custom_text'] === undefined) {
return null;
}
// 3. 更新用関数を取得
var { editPost } = useDispatch('core/editor');
return el(
PluginDocumentSettingPanel,
{
//パネルの名前、文字列、アイコンを指定
//nameはサイト内で一意である必要がある点に注意
name: 'my-custom-panel',
title: T.title, //ここをPHPから渡した変数にする
icon: 'admin-generic',
},
//TextControl(文字列)として処理
el(TextControl, {
//入力欄の上に表示する説明
label: T.label, //ここをPHPから渡した変数にする
//register_post_metaの第二引数で指定したメタキーの値を表示
value: meta['my_custom_text'] || '',
__next40pxDefaultSize: true,
onChange: function (newValue) {
// 3. メタデータの特定キーだけを上書きして送信
editPost({
meta: {
//register_post_metaの第二引数で指定したメタキーを指定
'my_custom_text': newValue
}
});
}
})
);
};
//MyCustomPanelという領域にmy-custom-panel-pluginという名前のパネルを出力する
//領域やパネル名は一意である必要がある点に注意
registerPlugin('my-custom-panel-plugin', { render: MyCustomPanel });
})(window.wp);
応用すると、先ほどの投稿タイプの指定もPHP側($post_types)からwp_localize_script()で渡して、不整合なく処理することもできますね。
複数のメタパネルの一括設定は慣れてからの方がいいかも
ここまで紹介したようにPHPとJSの呼応によって1つのメタパネルが完成することから、1つのJSファイル内に複数のパネルや領域のJSコードを挿入しても呼応するPHPコードがあればきちんと動作します。
更に、JSコード冒頭の定義部分が共通で領域が共通なものは、メタパネルの表示と動作部分を1つのJSコードのまとまりの中に書いたりすることもできます。
また、複数のコントロール用の定義をまとめておき、領域内に複数のコントロールを持つメタパネルを追加していくこともできます。
が、コードの流れと体系が分からないままこれらのことをしていくと、後々コードを見て「ここ何だっけ?やってみたけど動かない」という事態を招きかねません。
JSの定義部分については重複して記述があっても1回だけ読み込まれる(重複していれば読み込み済としてスキップされる)だけですし、同一領域へメタパネルを追加する記述の塊があってもきちんとその領域内に展開されますし、これらが重複していても人間には分からない位の一瞬の判断で処理が行われますから、「もうメタパネルについては空でもコードが書ける」位になるまでは、まとめて書かないようにしておいた方が無難だと思います。
ここまでで、メタパネルの基本的なコード体系、どのように動作するのか、リアルタイムコラボレーションが使えるようになることは確認いただけたと思います。
実際の運用ケースでは、テキスト入力以外の入力コントロールを行うことがほとんどだと思いますので、ここからは前述の文字列メタパネルのコードを一部変更していろいろなコントロール(入力・指定の方法)ができるようにするコード例を紹介していきます。
文字列メタパネルとのコードの違いなどを見ながら実装してみてくださいね。
テキストエリア(長文用)
文字列メタパネルの際と同様にPHPはfunctions.phpへ、JSはpwcn-metapanel.jsへコードを追加し、投稿編集画面を開きなおして動作確認をしてください(パネルが表示されない場合はキャッシュのクリアやコードの再確認をしてみてください)。
PHPコード
/*** テキストエリアのサンプル ***/
add_action( 'init', function() {
// 対象にしたい投稿タイプを配列で指定
$post_types = ['post'];
//メタキーを指定
$meta_key = 'my_custom_text_area';
foreach ( $post_types as $post_type ) {
register_post_meta(
$post_type,
$meta_key,
[
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
]
);
}
} );
※無名関数にしていますので、ユーザー定義関数を使いたい方はご自身で書き換えてください
JSコード
//テキストエリアの場合のJS(入力文字列カウント付き)
(function (wp) {
var el = wp.element.createElement;
var registerPlugin = wp.plugins.registerPlugin;
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
var useSelect = wp.data.useSelect;
var useDispatch = wp.data.useDispatch;
var TextareaControl = wp.components.TextareaControl; //テキストエリアの場合
var MyCustomPanel = function () {
// 1. 現在のメタデータを取得
var meta = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute('meta') || {};
}, []);
// 2.メタキーが定義されていない投稿タイプならフォームを非表示にする
// register_post_metaの第二引数で指定したメタキーを指定
if (meta['my_custom_text_area'] === undefined) {
return null;
}
var { editPost } = useDispatch('core/editor');
// 現在の値を定数に入れておく(文字数計算用)
//register_post_metaの第二引数で指定したメタキーを指定
var currentValue = meta['my_custom_text_area'] || '';
var charCount = currentValue.length;
return el(
PluginDocumentSettingPanel,
{
name: 'my-custom-textarea-counter',
title: 'テキストエリアパネル',
icon: 'edit',
},
el('div', {},
// メインのテキストエリア
el(TextareaControl, {
label: '長文文字列',
value: currentValue,
rows: 5, //行数
onChange: function (newValue) {
editPost({
//register_post_metaの第二引数で指定したメタキーを指定
meta: { 'my_custom_text_area': newValue }
});
}
}),
// 文字数カウンターの表示
el('div', {
style: {
textAlign: 'right',
fontSize: '12px',
color: charCount > 120 ? '#d94f4f' : '#666', // 120文字を超えたら赤くする例
marginTop: '0', // TextareaControlとの隙間を調整
paddingBottom: '10px'
}
},
charCount + ' 文字'
)
)
);
};
registerPlugin('my-custom-textarea-counter-plugin', { render: MyCustomPanel });
})(window.wp);
チェックボックス
文字列メタパネルの際と同様にPHPはfunctions.phpへ、JSはpwcn-metapanel.jsへコードを追加し、投稿編集画面を開きなおして動作確認をしてください(パネルが表示されない場合はキャッシュのクリアやコードの再確認をしてみてください)。
PHPコード
/*** チェックボックスのサンプル ***/
add_action( 'init', function() {
// 対象にしたい投稿タイプを配列で指定
$post_types = ['post'];
//メタキーを指定
$meta_key = 'my_custom_check';
foreach ( $post_types as $post_type ) {
register_post_meta(
$post_type,
$meta_key,
[
'show_in_rest' => true,
'single' => true,
'type' => 'string', //JS側でtrue/falseの場合はboolean、1/空白の場合はstringを使う
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
]
);
}
} );
※無名関数にしていますので、ユーザー定義関数を使いたい方はご自身で書き換えてください
JSコード
//チェックボックスのJS
(function (wp) {
var el = wp.element.createElement;
var registerPlugin = wp.plugins.registerPlugin;
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
var CheckboxControl = wp.components.CheckboxControl;
var useSelect = wp.data.useSelect;
var useDispatch = wp.data.useDispatch;
var MyCustomPanel = function () {
// 1. 現在のメタデータを取得
var meta = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute('meta') || {};
}, []);
// 2.メタキーが定義されていない投稿タイプならフォームを非表示にする
// register_post_metaの第二引数で指定したメタキーを指定
if (meta['my_custom_check'] === undefined) {
return null;
}
var { editPost } = useDispatch('core/editor');
return el(
PluginDocumentSettingPanel,
{
name: 'my-custom-check-panel',
title: '機能設定',
icon: 'admin-settings',
},
el(CheckboxControl, {
label: 'この機能を有効にする',
help: 'チェックを入れるとフロントエンドで特定の機能が動作します。',
//register_post_metaの第二引数で指定したメタキーを指定
checked: !!meta['my_custom_check'], // 二重否定(!!)で確実に boolean 型に変換
onChange: function (newValue) {
editPost({
meta: {
//register_post_metaの第二引数で指定したメタキーを指定
// newValue には true/false が入る(register_post_metaのtypeはbooleanにする)
//'my_custom_check': newValue
//newValue には 1/空文字 が入る(register_post_metaのtypeはstringにする)
'my_custom_check': newValue ? '1' : ''
}
});
}
})
);
};
registerPlugin('my-custom-check-plugin', { render: MyCustomPanel });
})(window.wp);
ラジオボタン
文字列メタパネルの際と同様にPHPはfunctions.phpへ、JSはpwcn-metapanel.jsへコードを追加し、投稿編集画面を開きなおして動作確認をしてください(パネルが表示されない場合はキャッシュのクリアやコードの再確認をしてみてください)。
PHPコード
/*** ラジオボタンのサンプル ***/
add_action( 'init', function() {
// 対象にしたい投稿タイプを配列で指定
$post_types = ['post'];
//メタキーを指定
$meta_key = 'my_custom_button';
foreach ( $post_types as $post_type ) {
register_post_meta(
$post_type,
$meta_key,
[
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
]
);
}
} );
※無名関数にしていますので、ユーザー定義関数を使いたい方はご自身で書き換えてください
JSコード
//ラジオボタンの場合のJS
(function (wp) {
var el = wp.element.createElement;
var registerPlugin = wp.plugins.registerPlugin;
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
var useSelect = wp.data.useSelect;
var useDispatch = wp.data.useDispatch;
var RadioControl = wp.components.RadioControl; // ラジオボタン用
var MyCustomPanel = function () {
// 1. 現在のメタデータを取得
var meta = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute('meta') || {};
}, []);
// 2.メタキーが定義されていない投稿タイプならフォームを非表示にする
// register_post_metaの第二引数で指定したメタキーを指定
if (meta['my_custom_button'] === undefined) {
return null;
}
var { editPost } = useDispatch('core/editor');
return el(
PluginDocumentSettingPanel,
{
name: 'my-custom-radio-panel',
title: 'ボタン設定パネル',
icon: 'admin-settings',
},
el(RadioControl, {
label: '表示モードを選択',
selected: meta['my_custom_button'] || 'default', // 現在の値(未設定ならdefault)
options: [
{ label: '標準(Default)', value: 'default' },
{ label: '目立たせる(Highlight)', value: 'highlight' },
{ label: '隠す(Hidden)', value: 'hidden' },
],
onChange: function (newValue) {
editPost({
meta: {
//register_post_metaの第二引数で指定したメタキーを指定
'my_custom_button': newValue
}
});
}
})
);
};
registerPlugin('my-custom-radio-plugin', { render: MyCustomPanel });
})(window.wp);
セレクトボックス
文字列メタパネルの際と同様にPHPはfunctions.phpへ、JSはpwcn-metapanel.jsへコードを追加し、投稿編集画面を開きなおして動作確認をしてください(パネルが表示されない場合はキャッシュのクリアやコードの再確認をしてみてください)。
PHPコード
/*** セレクトボックスのサンプル ***/
add_action( 'init', function() {
// 対象にしたい投稿タイプを配列で指定
$post_types = ['post'];
//メタキーを指定
$meta_key = 'my_custom_selection';
foreach ( $post_types as $post_type ) {
register_post_meta(
$post_type,
$meta_key,
[
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
]
);
}
} );
※無名関数にしていますので、ユーザー定義関数を使いたい方はご自身で書き換えてください
JSコード
//セレクトボックスのJS
(function (wp) {
var el = wp.element.createElement;
var registerPlugin = wp.plugins.registerPlugin;
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
var SelectControl = wp.components.SelectControl; // ここを変更
var useSelect = wp.data.useSelect;
var useDispatch = wp.data.useDispatch;
var MyCustomPanel = function () {
// 1. 現在のメタデータを取得
var meta = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute('meta') || {};
}, []);
// 2.メタキーが定義されていない投稿タイプならフォームを非表示にする
// register_post_metaの第二引数で指定したメタキーを指定
if (meta['my_custom_selection'] === undefined) {
return null;
}
var { editPost } = useDispatch('core/editor');
return el(
PluginDocumentSettingPanel,
{
name: 'my-custom-select-panel',
title: '表示設定',
icon: 'admin-settings',
},
el(SelectControl, {
label: '表示モードを選択',
// RadioControlでは "selected" でしたが、SelectControlでは "value" を使います
//register_post_metaの第二引数で指定したメタキーを指定
value: meta['my_custom_selection'] || 'default',
options: [
{ label: '選択1(Default)', value: 'default' },
{ label: '選択2', value: 'highlight' },
{ label: '選択3', value: 'hidden' },
],
onChange: function (newValue) {
editPost({
meta: {
//register_post_metaの第二引数で指定したメタキーを指定
'my_custom_selection': newValue
}
});
}
})
);
};
registerPlugin('my-custom-select-plugin', { render: MyCustomPanel });
})(window.wp);
カスタムフィールドの操作を行わない説明欄
文字列メタパネルなどのように入力窓が必要ないため、PHPへのコード追加はありません。JSはpwcn-metapanel.jsへコードを追加し、投稿編集画面を開きなおして動作確認をしてください(パネルが表示されない場合はキャッシュのクリアやコードの再確認をしてみてください)。
JSコード
(function (wp) {
var el = wp.element.createElement;
var Notice = wp.components.Notice; //WP標準の警告や通知などの背景スタイルを使いたい場合
var ExternalLink = wp.components.ExternalLink; //外部ページへのリンクを使いたい場合は追加
var registerPlugin = wp.plugins.registerPlugin;
var PluginDocumentSettingPanel = wp.editor.PluginDocumentSettingPanel || wp.editPost.PluginDocumentSettingPanel;
var MyNoticePanel = function () {
return el(
PluginDocumentSettingPanel,
{
name: 'my-notice-panel',
title: '【重要】設定上の注意',
icon: 'info-outline', // インフォメーションアイコン
},
// パネルの内部コンテンツ
el('div', { style: { padding: '10px 0' } },
el('p', { style: { fontSize: '13px', lineHeight: '1.5', color: '#1e1e1e' } },
'説明文のみを出力するパネルです',
el('br'),
'文字列やリンクなどいろいろなことを表示させることができます'
),
el('p', { style: { marginTop: '10px', fontWeight: '600' } },
'⚠️ 注意:',
el('br'),
'JSの作法に従ってHTMLタグを使って記述していきます'
),
el(ExternalLink, { href: 'https://example.com/docs' }, '詳細なマニュアルはこちら'),
el(Notice, {
status: 'warning', // 'error', 'info', 'success', 'warning'
isDismissible: false // 消去ボタンを隠す
}, '内部にこのような警告文を表示することもできます')
)
);
};
registerPlugin('my-notice-panel-plugin', { render: MyNoticePanel });
})(window.wp);
メタボックス方式からの移行方法、既知の懸念点など
メタボックスからメタパネルへの移行方法の例
カスタムフィールドの追加ではなく登録を行う
通常「add_post_meta()」を使っていろいろな設定値を指定した後に「add_metaboxes」や「admin_init」へフックさせてメタボックスを表示させるのがコードの流れですが、メタパネルでは登録したカスタムフィールドの設定を元にJSで情報を読み書きする窓を作るという流れになります。従って、前項のサンプル(以下に再掲)のように、PHPでは「register_post_meta()」を使い、REST APIから利用できるようにする条件を追加します。
/*** テキストのサンプル ***/
add_action( 'init', function() {
register_post_meta( 'post', 'my_custom_text', [
'show_in_rest' => true, // これでREST APIの "meta" 内に出現する
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
] );
} );
ユーザー定義関数を使う場合は以下のような形になります。
/*** テキストのサンプル ***/
function pwcn_register_my_custon_text_field(){
register_post_meta( 'post', 'my_custom_text', [
'show_in_rest' => true, // これでREST APIの "meta" 内に出現する
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
] );
add_action('init','pwcn_register_my_custon_text_field');
上記のコードをこれまでのadd_post_meta()が書かれている関数の下あたりにコピーし、書かれているカスタムフィールドキーをこれまでのキーと同一にします(独自のユーザー定義関数の形にする場合はサイト上で重複しない関数名に書き換えてください)。
一旦add_post_meta()を適用させたり、カスタムフィールド値の保存を行う以下のようなアクションフックをコメントアウトして無効にします。
//add_action('add_meta_boxes','your_functionname');
//add_action('admin_init','your_functionname');
//add_sction('save_post','your_functionname');
旧メタボックスの表示・更新を行う上記のアクションフックを残したままメタパネルを実装した場合、メタパネルから更新したデータはエディターの「更新」「下書き保存」「公開」などをクリックした際(つまりsave_postが処理された段階)でメタパネルの変更データは破棄され、旧の値に戻され、一見更新できないと勘違いすることとなりますのでご注意ください
完了したら、本ページのJSを参考にこのカスタムフィールドキーに対応するJSを作り、読み込ませます。
投稿編集画面を開き、メタパネルが表示され、今まで入力したメタキーに対する値が表示されていること、更新が問題なくできることが確認できれば移行自体は完了です。
今まで使用していたメタボックスが不要な場合はこのままコメントアウトしておいてもいいですし、add_post_meta()のあるユーザー定義関数、参照しているコールバック関数、アクションフックを削除すればメタボックスからメタパネルへの完全移行は完了です。
クラシックエディターではメタパネルは使えません。もしもクラシックテーマでもカスタムフィールドのフォームによる編集をしたい方はこちらのページを参考にしながら両立させるのも手かも知れませんが、ブロックエディターを常用している、またはブロックエディターのみに対応させるのであればこれら旧メタボックス用コードは不要になります。
メタパネルへの移行でよくあるトラブル
メタパネルが表示されない
コードを見てお分かりの通り、今回の実装ではメタパネルの表示・更新に関するものはすべてJSに書かれています。
パネル自体が表示されない、パネルは表示されるが値が入力できないといったトラブルが発生した場合は以下を検証してみてください。
- JSの読み込みが正常に行われているか(デベロッパーツールを開いて「×」となっていないか)
- JSの内容が正しく記述されているか(特に数か所あるカスタムフィールドキーの指定間違いなどがないか)
メタパネルに入力した値が更新されない
ここまでで何度か書いている通り、以下が有効な状態でエディターの「更新」「公開」「下書き保存」を行った場合メタパネルの情報は保存されません。
- WordPress標準のカスタムフィールド(カスタムフィールドの一覧)が有効になっている場合
- 同じカスタムフィールドキーに対してメタボックスの表示や更新のプログラムが並行して実行されている場合
JS自体に問題がなければ、今一度本ページを読み返してこれらを無効にすることにより正常に更新されるようになります。
経験上、特に移行の場合はこの「更新されない」という不具合に無駄な時間を割くことが多いので、まずは上記の機能や機構を止めることからスタートすることをおすすめします
メタボックスとの違い
メタボックスは追加すると、コードの書き方によって「右サイドバー(カテゴリー設定などの下)」か「編集画面の下部(カスタムフィールド一覧の上など)」に配置され、WordPress標準のメタパネルの下であれば、上下の移動やサイドから本文下、本文下からサイドへの移動もできるようになっています。
しかしながら、メタパネルは、基本的にはサイドバーの中以外の場所には配置できず、コードの読み込み順によって表示位置が決まり、移動することもできません。テストした感触では基本的に「プラグイン」「テーマ」「WordPress標準」の順でコードの読み込み順に配置されるようですから、位置を変えれるようにしたい、長文などを本文下で入力させたいなどといったケースではメタボックスを利用したほうがいいかも知れません。
この機構への変更で受けられる恩恵がある
今一度書いておきますが、今回の移行は以下の手順で行います。
- エディターの「カスタムフィールド」欄の停止
- 「add_post_meta() – 追加」から「register_post_meta() – 登録」への変更
- パネルと値の更新を行うJSの読み込みとJSコードの追加
カスタムフィールドキーを追加から登録へ変更することで、WordPressの最近のバージョンで追加された、カスタムフィールドの値を呼び出しやすくする「Block Bindings API」というのを使う準備も同時に整えることができます。
「Block Bindings API」を使うことで、特にアーカイブなどの一覧でのカスタムフィールドの呼び出しがしやすくなりますのでぜひ併用してください。
【考察】メタボックスの今後
今回のように、WordPressは今までPHPで何かを行っていたものから、ブロックエディターの導入によって、REST APIを使って更新していく形のものが増えていくことが予想されます。
ただWordPressは必ず新機能が出ると旧来の方式に対する互換性の維持ができるように、いろいろな方が試行錯誤して方法を見つけ出してくれるありがたいCMSでもあります(私の経験上この機能は完全廃止というのはなかったように思います)。
今回のリアルタイムコラボレーション(RTCと公式では略されています)でのメタボックスの扱いに関しては、RTCの導入以前からメタボックスが保存時に情報を更新する=リアルタイムに更新がかからない=データの不整合が起こるという懸念に関していろいろと議論が行われ、RTCは導入することとし、メタボックスがある場合にはRTCを有効にしていたとしても機能させないように一旦するという形になったようです。
今後この問題については継続して議論されていき、例えばメタボックスのままリアルタイムに更新するようなフック等が作られたりして対応できるようになるなどといった対応がなされるか、今回のようにPHPとJS(基本開発環境でそれなりの知識を持って記述しないと実装困難な形)ではなく、同じく7.0で追加されたPHPのみでブロックを作れるようにするといったような形でPHPだけでメタパネルが作れるようになったりという対応がされるかも知れません。
最もメタボックスで弊害が出るのは現状RTCだけなので、RTCを使わないことが前提であれば(自身で更新するだけ、または共同編集する必要がないのであれば)、現状のメタボックスの形でも構いませんし、以下のページのように一旦RTC有効化時にはメタボックスを表示させないようにするといった措置でいいかも知れません。
さらに言えば、サイトにインストールしているメタボックスを使うプラグイン(特にSEOやセキュリティ系のプラグイン)すべてが今回のようにメタパネルにしたり、RTC有効化時にはメタボックスの表示を無効にしたりといった措置を講じなければRTCは使えない話ですから、未来のためにどうしておくべきかを考えて、メタパネルを使用するかの判断をするといいと思います。










コメントを残す