Gutenbergエディタ(ブロックエディタ)にボタンを追加する

WordPress

WordPressのバージョンが5.0になり、エディタが新しくなりました。

新しい Gutenberg 編集エクスペリエンス
コードネームは「Gutenberg」、WordPress の新しい編集エクスペリエンスが現在開発中です。詳細をお読みの上、テストしてみてください。

これまでのTinyMCEとは異なりReactを利用したモダンな実装になっており、エディタへの機能の追加方法も大きく変わりました。

ここでは選択した文字列を特定のクラスを持ったspanで囲うボタンの追加方法を紹介します。

実装するもの

PHPとJavaScript、CSSを編集します。

PHP側は適当に作成したプラグインのmy_plugin.php、JavaScriptとCSSはそのプラグイン配下に作成することを想定しています。

今回はReactを使用しない方法になります。

そのためフロントエンドのビルド環境の用意は必要ありません

JavaScriptやCSSを登録

TinyMCEの時はJavaScriptとCSSの登録は別々でしたが、Gutenbergでは「enqueue_block_editor_assets」アクションをフックして「wp_enqueue_style」や「wp_enqueue_script」を使用して登録します。

wp_enqueue_style
void wp_enqueue_style( string $handle ] ] ] ) 使用するスタイルシート(CSS)を出力用のキューに入れる。パラメータ$srcが指定された場合は、グローバル変数$wp_stylesに登録してから出力用のキューに入れる。
wp_enqueue_script
void wp_enqueue_script( string $handle ] ] ] ) スクリプト(JavaScript)の重複出力を回避するために、使用するスクリプトを出力用のキューに入れる。パラメータ$srcが指定された場合は、グローバル変数$wp_scriptsに登録してから出力用のキューに入れる。

「wp_localize_script」でJavaScript側にデータを渡すことも可能です。
下の例ではボタンに表示されるタイトルとクラス名をPHP側から渡せるようにしています。

wp_localize_script
bool wp_localize_script( string $handle, string $object_name, array $l10n ) スクリプト向けの変数を追加する。

ここでは「wp_enqueue_script」の依存関係に「wp-element」「wp-rich-text」「wp-editor」を追加します。
後で追加するJavaScriptでこれらを使用するためで、もし他に依存するもの(wp-datawp-i18n など)を使用する場合はそれらを追加します。
ここで追加した依存関係によってJavaScriptファイルの読み込み順をWordPressが適切に判断してくれるようになります。

my_plugin.php

add_action( 'enqueue_block_editor_assets', function () {
   wp_enqueue_style( 'my_plugin', plugins_url( 'assets/css/editor.css', __FILE__ ) );
   wp_enqueue_script( 'my_plugin', plugins_url( 'assets/js/editor.js', __FILE__ ), [
      'wp-element',
      'wp-rich-text',
      'wp-editor',
   ] );
   wp_localize_script( 'my_plugin', 'my_plugin_obj', [
      'title' => 'My Plugin',
      'class' => 'my-plugin',
   ] );
} );

CSSを編集

クラスで囲われたかどうかをわかりやすくするため装飾します。

assets/css/editor.css

.my-plugin {
    display: inline;
    background-position: left -100% center;
    background-repeat: repeat-x;
    background-image: linear-gradient(to right, rgba(255, 255, 255, 0) 50%, #ff6 50%);
    background-size: 200% .6em;
    font-weight: bold;
    padding-bottom: .6em;
}

ここではクラスで囲われた箇所に蛍光ペンを引いたような装飾をつけています。

この装飾はエディタ用です。

実際にフロント側で何かデザインをつけるためには別途フロント用のCSSを用意して読み込ませるようにする必要があります。

JavaScriptを編集

先ほど依存関係に登録した「wp-element」「wp-rich-text」「wp-editor」はそれぞれ「window.wp.element」「window.wp.richText」「window.wp.editor」として使用できます。

以下のように短い名前で使用できるようにしておきます。

(function (richText, element, editor) {
    
}(
    window.wp.richText,
    window.wp.element,
    window.wp.editor
));

ボタンを追加するには「richText」の「registerFormatType」を使用します。

WordPress/gutenberg
The Block Editor project for WordPress and beyond. Plugin is available from the official repository. - WordPress/gutenberg

ここでは「title」「tagName」「className」「edit」を登録します。

assets/js/editor.js

(function (richText, element, editor) {
    const name = 'my-plugin/my-plugin';
    richText.registerFormatType(name, {
        title: my_plugin_obj.title,
        tagName: 'span',
        className: my_plugin_obj.class,
        edit: function (args) {
            return element.createElement(editor.RichTextToolbarButton, {
                icon: 'admin-customizer',
                title: my_plugin_obj.title,
                onClick: function () {
                    args.onChange(richText.toggleFormat(args.value, {
                        type: name
                    }));
                },
                isActive: args.isActive,
            });
        },
    });
}(
    window.wp.richText,
    window.wp.element,
    window.wp.editor
));

my_plugin.phpwp_localize_script を使用して登録したタイトルとクラス名をそれぞれ

  • my_plugin_obj.title
  • my_plugin_obj.class

として使用しています。
PHPから渡す必要がない場合は直接JavaScriptファイルにタイトルとクラス名を書いても動作します。

editor.RichTextToolbarButton

WordPress/gutenberg
The Block Editor project for WordPress and beyond. Plugin is available from the official repository. - WordPress/gutenberg

ToolbarButton

WordPress/gutenberg
The Block Editor project for WordPress and beyond. Plugin is available from the official repository. - WordPress/gutenberg

iconに設定するアイコンは以下のページから選択可能です。

Dashicons | WordPress Developer Resources
WordPress/gutenberg
The Block Editor project for WordPress and beyond. Plugin is available from the official repository. - WordPress/gutenberg

ここまでの処理で以下のようにボタンが追加されます。

動作確認

文字を選択した状態でボタンを押すと蛍光ペンを引いたような装飾がされました。

「HTMLとして編集」から確認すると「my-plugin」クラスのspanで囲われていることが確認できます。

装飾されている箇所にカーソルが当たっている状態だとボタンが選択されたような表示になり、この時にボタンを押すと装飾が外れ、「my-plugin」クラスのspanで囲われていたものが外れます。

追記:複数のボタンを追加

コメントで複数追加する場合の質問があったので追記します。

richText.registerFormatType

を使用すればいくつでもボタンを追加ことが可能です。
ただし、同じクラス名や複数のクラス名を指定することはできません。

Gutenberg複数追加例
Gutenberg複数追加例. GitHub Gist: instantly share code, notes, and snippets.

まとめ

Reactで作られた新しいエディタでも、ビルド環境を用意することなく割と気軽にエディタへの機能の追加が可能になっていることがわかりました。

ブログのメイン機能と言っても過言ではないエディタへの大きな変更が今後のCMS界隈にどう影響していくのかが気になります。

追記:プラグインを作成しました

Add RichText Toolbar Button
This plugin makes it easy to add RichText toolbar button.

通常の方法ではいくつかのボタンをまとめてドロップダウンにしたり複数クラスを指定したりカラーピッカーやフォントサイズピッカーを追加することはできませんが、このプラグインではそれらが実現可能です。

コメント

  1. はらだちせ より:

    わかりやすい記事ありがとうございます。
    とても参考になりました。
    ボタンを複数登録する場合はどうしたらいいのでしょうか?

  2. はらだちせ より:

    ご対応ありがとうございます。
    何度もすみません、、、。
    参考コードを試してみました。
    ボタン表示はされるのですが、次はクラスが付与されなくなりました。
    コードはphpとjsファイルにそのままコピーしたので記述ミスではないと思うのですが・・・。

  3. はらだちせ より:

    ありがとうございます。
    無事にできました。

    今後も素敵な記事執筆楽しみにしています。

  4. けんいち より:

    大変参考になりました。
    こちらのカスタマイズをプラグインではなく子テーマに直接する場合の書き方は、どうなりますか?
    初心者で分からなかったので、教えていただけたら幸いです。

    • technote より:

      子テーマでのカスタマイズ例をgistに載せたので参考にしてみてください。
      以下のような構成になります。

      child-theme/editor.js
      child-theme/functions.php
      child-theme/style.css

      https://gist.github.com/technote-space/0fa781400bd143cae75eaff3acafb24c

      「test-class」などを適当なクラス名に変更します。
      Gutenbergエディタでも「style.css」を読み込むようにしてあるテーマを想定しています。

      もしGutenbergエディタで「style.css」が読み込まれない場合は以下を参考にしてください。
      https://gist.github.com/technote-space/4f8589448e5357e5cd9dc437d5a6902d

      • けんいち より:

        早速のご返答ありがとうございます。
        無事に子テーマでのカスタマイズが出来ました。

        少し教えていただきたいのですが、ダッシュアイコンにbackgroundを付けたいのですが、特定のクラスなどは付きますか?それとも付けることが出来ますでしょうか?

        ど素人なもので意味不明な発言していたら申し訳ございませんが、よろしくお願いいたします。

  5. technote より:

    RichTextToolbarButtonにも「className」で任意のクラス名を付けることができます。
    https://gist.github.com/technote-space/0fa781400bd143cae75eaff3acafb24c/revisions#diff-7ea2683d6f213926d1bc30eb2fbf4503
    参考にして試してみてください。

  6. けんいち より:

    無事に出来ました。
    本当にありがとうございました。