ワードプレスのエディター「Gutenberg」にカスタムブロックを追加する方法

こんな感じでアバター付きの吹き出しコメントを表示するブロックを作成してみましたが、どうでしょう?
エディタ「Gutenberg」ではページのコンテンツをブロック毎に管理・編集することが出来ますので、ワードプレスでブログをやっていたり、記事を書くことの多い方には、便利なブロックが増えると有り難いですよね。
例として作成したチャット形式のブロックに限らず、スライダーやら特別なレイアウトのセクションなど、あらゆるブロックを挿入することができれば、Gutenbergがコンテンツ作成も楽しんで書くことができる便利なツールとなる筈です。
それに実はブロックって結構簡単に実装できますし、痒いところに手が届くようなブロックが欲しいなら、ブロックの作成方法は知っておいて損はしないですよ。
ブロックの追加に必要なファイル
Gutenbergのブロック編集では主にJavaScriptを使用しますので、JavaScriptを使い慣れている方が好ましいです。それに加えて、スタイルを定義するためのCSSファイルが2つ必要になります。
- block.js(ブロックを追加)
- block-style.css(フロントエンド用)
- block-editor-style.css(編集画面用)
ファイル名は管理しやすいもので別に何でも構いませんが、拡張子だけは.jsと.cssでお願いします。
GutenbergではReactを使用しているので、Reactを使い慣れていると編集は非常に楽になると思います。ちょっとデータを保存する方法が異なるだけで使えるようになります。
僕はReactを使ったことがありませんでしたが、ブロック編集を勉強するついでにある程度覚えられたくらいですので、凝ったものを作ろうとしない限り、事前にReactを使いこなせている必要は無い筈です。
また少しだけPHPにコードを書く必要もありますが、ほんの少しですのでワードプレスに慣れている方なら楽勝です。
PHP側で必要なコード
では、まずはワードプレスにブロックを追加するCSSとJavaScriptをロードするためのコーディングを施していきます。
具体的に必要な処理は以下の2点のみですのでパパっと書いてしまいましょう。
- ブロックを登録するJavaScriptと編集画面用のCSSをロードさせる
- フロントエンド(実際に表示されるページ)用のCSSをロードさせる
ブロックを登録するコードをロードさせる
必要なコードは以下のとおりです。
add_action( 'enqueue_block_editor_assets', 'register_block_type' );
function register_block_type() {
// CSSのハンドル
$block_style_handle = 'your-custom-block';
// CSSファイルの登録
wp_enqueue_style( $block_style_handle, PATH_TO_YOUR_CSS_FILE );
// JavaScriptのハンドル
$block_script_handle = 'your-custom-block';
// JavaScriptファイルの登録
wp_enqueue_script( $block_script_handle, PATH_TO_YOUR_JS_FILE, array( 'wp-blocks', 'wp-element', 'wp-components' ) );
}
これが基本的な形になります。
必要に応じて依存するJSファイルのハンドルに「wp-i18n」「lodash」を追加するなどしてください。
ちなみに「PATH_TO_YOUR_CSS_FILE」「PATH_TO_YOUR_JS_FILE」はブロックを追加するためのCSSファイルとJavaScriptファイルのURLとなりますので、任意のファイルの指定してください。
フロントエンド側にスタイルを出力
こちらはテーマなどでもお馴染みの方法です。
add_action( 'wp_enqueue_scripts', 'enqueue_block_style' );
function enqueue_block_style() {
// CSSのハンドル
$block_style_handle = 'your-custom-block-style';
// CSSファイルの登録
wp_enqueue_style( $block_style_handle, PATH_TO_YOUR_CSS_FILE );
}
ただ、個人的にはページスピードを意識すると、テーマにブロックを追加するのであれば、テーマから出力されるCSSファイル内に統一して定義し、プラグインとしてブロックを追加するのであれば、インラインで出力することをオススメします。
ブロックのカテゴリーを追加する方法(オプション)
本当に簡単なので以下のコードをコピペして、「slug」「title」「icon」の値をそれぞれ編集するだけでカテゴリーは追加できます。
add_filter( 'block_categories', 'register_block_categories', 10, 2 );
function register_block_categories( $block_categories, $post ) {
return array_merge(
$categories,
array(
array(
'slug' => 'your-block-category',
'title' => __( 'Your Block Category', 'your_textdomain' ),
'icon' => 'admin-plugins',
),
)
);
}
余談として、第二引数で投稿データを取得できますので、投稿タイプやフォーマットなどにより、ブロックカテゴリーの制御もできます。
JavaScript側で必要なコード
まだ白紙の状態ですが、以下のコードが基本的な形で、JSX抜きに書いていくとこんな感じになるかと思います。
// 翻訳用の関数
const { __ } = wp.i18n;
// ブロックを登録するのに必要な関数
const { registerBlockType } = wp.blocks;
// 要素を生成する関数
const el = wp.element.createElement;
// ブロックとして登録するID
const blockName = 'your-block/sample'
// 登録
registerBlockType( blockName,
{
// タイトル
title: __( 'Your Sample', 'your_textdomain' ),
// アイコン
icon: 'universal-access-alt',
// カテゴリー
category: 'widgets',
// 詳細
description: __( 'This is a sample block.' 'your_text_domain' ),
// 保存されるデータ
attributes: {
sampleAttr: {
type: 'string',
default: 'default string value'
}
}
// 編集画面のブロックとして出力
edit: function( props ) {
// データを保存する関数
const { setAttributes } = props;
// 保存されているデータ
const { sampleAttr } = props.attributes;
// HTMLを生成
return el(
'div',
{
className: 'your-block-wrapper edit-mode'
},
el(
'input',
{
onChange: value => setAttributes( { sampleAttr: value } ), // データを保存
value: sampleAttr
}
)
);
}
// 実際にコンテンツのブロックとして出力
save: function( props ) {
// 保存されているデータ
const { sampleAttr } = props.attributes;
// HTMLを生成
return el(
'div',
{
className: 'your-block'
},
el(
'p',
{
className: 'your-block-text'
}
sampleAttr
)
);
}
}
);
上に書いたサンプルでは、ブロック「ウィジェット」に追加する形になっています。ブロックを登録する関数はこんな形です。
registerBlockType( blockId, Object );
次に第二引数としてのオブジェクトですが、まず「edit」と「save」以外を覚えましょう。
- title: タイトル
- icon: アイコン(上の例ではDashiconを使用。SVGなども使用できます)
- category: カテゴリー(ブロックを追加する際に出てくるパネルにある区分。「common」「formatting」「layout」「widgets」「embed」「reusable」が標準)
- description: 詳細
- attributes: ブロックに使用される編集可能なデータリスト
これらは通常のオブジェクトタイプのキーと値ですので、通常のJavaScriptと同じと思って大丈夫です。
そして次に「edit」と「save」ですが、これらに書かれている部分がReactが使用されている部分です。
「edit」と「save」ではレンダリングされる値を返す
ここでちょっと知っておきたいのがJSXの存在です。今まで使ったこと無い方は「Babel · The compiler for next generation JavaScript」 へ一度移動してみてください。ウェブ上の変換ツールのページです。左側にHTMLらしきコードを入力すると、何やら右側に変換されたJavaScriptのコードが出力されるのが見て分かると思います。そして、そこには「React.createElement」というコードがいくつか登場しています。
この左側にあるコード、HTMLらしきコードと書きましたが、実はこれがJSXというやつです。HTMLを書いても恐らく問題なく機能すると思いますので、見慣れない方は暫く変換して形だけでも見慣れてください。また別の機会に紹介できればと思いますが、基本的な形は以下を参照。
// JSX
<Fragment>
<HTMLタグ名1 プロパティ名1="値1" プロパティ名2={ 変数1 } />
<コンポーネント名1 { ...オブジェクト } >{ 文字列変数 }</コンポーネント名1>
</Fragment>
これを変換するとだいたいこんな感じです。
実際はエンコードされますが、分かりやすいように書いています。
// JS
React.createElement(
Fragment,
null,
React.createElement(
'HTMLタグ名1',
{
プロパティ名1: "値1",
プロパティ名2: 変数値1
},
),
React.createElement(
コンポーネント名1,
オブジェクト,
文字列変数
)
);
// Gutenberg版
wp.element.createElement(
Fragment,
null,
wp.element.createElement(
'HTMLタグ名1',
{
プロパティ名1: "値1",
プロパティ名2: 変数値1
},
),
wp.element.createElement(
コンポーネント名1,
オブジェクト,
文字列変数
)
);
GutenbergではこのJSXを変換した右側にあるコードを更にGutenberg用に置き換えたコードが使用されます。僕がさっき上に書いたコードを見ると「React.createElement」が使用されていないことが分かると思います。これはワードプレスが管理しやすいように「wp.element.createElement」に置き換えているためで、Gutenbergにブロックを追加するにはこれが必要になります。
最初の例に書いたコードをHTMLに変換すると、
// edit
<div class="your-block-wrapper edit-mode"><input value="{ sampleAttr }" onChange="setAttributes( { sampleAttr: changedValue } )" /></div>
// save
<div class="your-block"><p class="your-block-text">{ sampleAttr }</p></div>
のような感じになりますが、実際にはワードプレスが用意してくれているコンポーネント(JSXで使用可能なテンプレートパーツ)も使っていくことになるので、このHTMLっぽいのは「何となくこんな感じかな?」と思える程度の認識で大丈夫です。
最終的にCSSでスタイルを付けられるようなHTMLの形になってくれれば問題無しです。
データの保存方法
Reactにはデータを更新するためのメソッド「setState」が備わっていますが、Gutenbergでは値を保存するための関数「setAttributes」が引数として受け取るプロパティ「props」に用意されています。使い方は「setAttributes( { attrName: Value } )」の様に更新されるキーと値をセットにしたオブジェクトを渡す形となっており、Reactの「setState」の代わりに使用すればいいと思います。ええ、Gutenbergでは「setState」は使用せず、「setAttribute」で必要なデータを保存して更新します。
先程のサンプルのようにフォーム要素のinputなどでは、onChangeなどのイベントコールバックを用意して、そのコールバックにより「setAttributes」がコールされるように書きましょう。
コンポーネントクラスを作成して、部分的なファイルの使い方をする場合だと、各コンポーネントに渡すプロパティに「{ …props }(或いは{…this.props})」という形にしておくことで、子コンポーネントにもデータ更新用のメソッド「setAttributes」を渡すことができ、親コンポーネントのデータを更新することができます。ReactのStateのリフトアップをsetAttributesを親コンポーネントから子コンポーネントに渡して使うことで簡単に解決されます。
実はブロックの追加方法は2種類存在する
ワードプレスではテーマやプラグインの殆どがPHPで書かれているように、実はこのブロックもPHP側で生成する方法が用意されています。
保存されるブロックのHTMLもJavaScript側で定義していく形になりますが、PHP側でフロントエンドに出力する際のHTMLを生成する関数を「register_block_type」のオプショナルの引数として用意されている「render_callback」に渡すことも可能です。その場合、合わせて保存されるべきデータを「attributes」として登録しておく必要がありますが、こちらもまたの機会に。とりあえず、関数の参照ページへのリンクは張っておきます。
3件のピン
[…] 関連記事:ワードプレスのエディター「Gutenberg」にカスタムブロックを追加する方法 […]
[…] 「ワードプレスのエディター「Gutenberg」にカスタムブロックを追加する方法」で紹介した方法と実際にブロックを追加する作業を比較すると大きく異なるのが、レンダリングされるHTMLを […]
[…] 関連記事: ワードプレスのエディター「Gutenberg」にカスタムブロックを追加する方法 […]