WordPress Gutenbergのリッチテキストツールバーにドロップダウンメニューボタン追加

WordPressのブロックエディタのリッチテキストツールバーに新たなドロップダウンメニューボタンを追加する方法を紹介します

ブロックエディタ (Gutenberg) になってから、カスタマイズの難易度があがり、Gutenberg用の開発環境を構築して、React, Webpack, Babel 等を使わざる得ない状況になってきています。

ただ、ブロックエディタのカスタマイズ情報はまだ少ないですし、 Webpack, Babel 等を使うとトランスパイル後のコードしか公開されない場合も多く、オープンソースと言いながら肝心のソースコードが見れなかったり、見れても 手軽に試せない場合も多いのでカスタマイズの敷居がだいぶ高くなっちゃっています (>_<)

そこで、今回はこれらの開発環境がなくてもコピぺで試せるコードを紹介します

いきなり実サイトの functions.php を編集せずにまずはローカルのテスト環境を構築してそこで編集してください

functions.php に CSS/JS 読み込み処理追加

お使いのテーマ(多くの場合はその子テーマ)の functions.php に以下の cp-richtext-style.css と edit_richtext.js ファイルを読み込む関数を追加します

function cp_richtext_init() {
    wp_enqueue_style( 'cp-richtext-style', get_stylesheet_directory_uri() . "/cp-richtext-style.css");
    if(is_admin()){
        wp_enqueue_script( 
            'cp-richtext-js',
            get_stylesheet_directory_uri() . "/edit_richtext.js",
            array( 'lodash', 'wp-rich-text','wp-element','wp-components', 'wp-blocks', 'wp-block-editor', 'wp-keycodes'),
            null,
            true 
        );
    }
}
add_action( 'enqueue_block_editor_assets', 'cp_richtext_init' );
add_action( 'wp_enqueue_scripts', 'cp_richtext_init' );

次にここで読み込んでいる2つのファイルを用意します

cp-richtext-style.css ファイルについて

このファイルは今回追加したアンダーラインマーカースタイルを反映させるためのCSSファイルです

以下のコードをコピーして cp-richtext-style.css という名前のファイルとして、functions.php と同じフォルダーに保存してください

mark.style-linemaker {
  background: linear-gradient(transparent 60%, #adff2f 60%);
}  

edit_richtext.js ファイルについて

このファイルはエディタ編集画面のリッチテキストツールバーに編集用メニュー項目を追加する JavaScriptファイルです

以下のコードをコピーして edit_richtext.js という名前のファイルとして、functions.php と同じフォルダーに保存してください

(function () {
    const { Fragment, createElement } = wp.element;
    const { registerFormatType, toggleFormat } = wp.richText;
    const { RichTextToolbarButton, RichTextShortcut, BlockFormatControls } = wp.blockEditor;

    const el = createElement;

    const tagTypes = [];
    tagTypes.push({ tag: 'mark', class: null, title: 'mark (マーカー)', icon: 'edit' });
    tagTypes.push({ tag: 'mark', class: 'style-linemaker', title: 'mark (アンダーラインマーカー)',icon: 'edit' });

    tagTypes.map( (idx) => {
        let type = 'celtis/richtext-' + idx.tag;
        if(idx.class !== null){
            type += '-' + idx.class;
        }
        registerFormatType( type, {
            title: idx.title,
            tagName: idx.tag,
            className: idx.class,

            edit( { isActive, value, onChange } ) {
                return (
                    el( Fragment,
                        {},
                        el( RichTextToolbarButton,
                            { icon: idx.icon,
                              title: idx.title,
                              isActive: isActive,
                              onClick: () => onChange( toggleFormat(value, { type: type })),
                            }
                        )
                    )
                );
            },
        });
    }) 
    
}());

これで、リッチテキストツールバーにマーカーとアンダーラインマーカーの2つのメニューが追加されます

独自タグの追加

例えば span タグを追加するには、tagTypes.push の部分をカスタマイズします

  1. tag を span にして、class に指定したいクラス名をセットします
  2. 指定したクラスのCSS定義を cp-richtext-style.css へ追加します

例.
コード:tagTypes.push({ tag: 'span', class: 'large-font', title: 'span (大きな文字)', icon: 'edit' });
CSS:.large-font { font-size: 1.5em; margin-left: 4px; margin-right: 4px; }

動作確認

上記の作業が終わったら編集した functions.php, cp-richtext-style.css, edit_richtext.js の3つのファイルをテーマに設置して動作することを確認します

編集画面の段落ブロック等でリッチテキストツールバーを確認

こんな感じになります

リッチテキストツールバーからマーカースタイルを指定

文章内から適用する文字範囲を選択して、ドロップダウンメニューからマーカー等を指定すれば選択範囲にタグが挿入されて指定したCSSが反映されます

投稿を公開して表示を確認

投稿記事を保存して公開します

投稿を表示して、ちゃんとマーカー等が表示されていればOKです

ここまで問題なく表示されることを確認したら、FTP等を使い3つのファイルを実サイトの テーマ内へコピーすれば使用できるようになります

専用ドロップダウンメニューへまとめるには

リッチテキストの通常のドロップダウンメニューではなく、専用に別のドロップダウンメニューとしてまとめるコードについても紹介します

先ほど作成した edit_richtext.js を以下のように変更します

(function () {
    const { Fragment, createElement } = wp.element;
    const { registerFormatType, toggleFormat } = wp.richText;
    const { RichTextToolbarButton, RichTextShortcut, BlockFormatControls } = wp.blockEditor;

    const { Fill, Slot, Toolbar, ToolbarButton, DropdownMenu } = wp.components;
    const { displayShortcut } = wp.keycodes;
    const { orderBy } = lodash;

    const el = createElement;

    function CeltisRichTextToolbarButton( { name, shortcutType, shortcutCharacter, ...props } ) {
        let shortcut;
        let fillName = 'CeltisToolbarControls';
        
        if ( name ) {
            fillName += `.${ name }`;
        }
        
        if ( shortcutType && shortcutCharacter ) {
            shortcut = displayShortcut[ shortcutType ]( shortcutCharacter );
        }
        
        return (
            el( Fill, 
                { name: fillName },
                el( ToolbarButton,
                    props,
                    { shortcut: shortcut }
                ),                  
            )  
        );
    };

    //専用のドロップダウン用ボタンとメニューを登録
    registerFormatType( 'celtis/dropdown', {
        title: 'buttons',
        tagName: 'dropdown',
        className: null,

        edit( { isActive, value, onChange } ) {
            return (
                el( BlockFormatControls, 
                    {},
                    el( 'div', 
                        { className: 'editor-format-toolbar block-editor-format-toolbar' },
                        el( Toolbar, 
                            {},
                            el( Slot, 
                                { name: 'CeltisToolbarControls' },
                                (fills) => {
                                    return ( fills.length !== 0 &&
                                        el( DropdownMenu, 
                                            { icon: 'smiley',
                                              label: 'Celtis Buttons',
                                              hasArrowIndicator: true,
                                              position: 'bottom left',
                                              controls : orderBy( fills.map( ( [ { props } ] ) => props ), 'title'),
                                            }
                                        )
                                    );
                                }
                            )
                        ),   
                    )
                )
            );
        }
    });
    
    const tagTypes = [];
    tagTypes.push({ tag: 'mark', class: null, title: 'mark (マーカー)', icon: 'edit' });
    tagTypes.push({ tag: 'mark', class: 'style-linemaker', title: 'mark (アンダーラインマーカー)',icon: 'edit' });

    tagTypes.map( (idx) => {
        let type = 'celtis/richtext-' + idx.tag;
        if(idx.class !== null){
            type += '-' + idx.class;
        }
        registerFormatType( type, {
            title: idx.title,
            tagName: idx.tag,
            className: idx.class,

            edit( { isActive, value, onChange } ) {
                return (
                    el( Fragment,
                        {},
                        // RichTextToolbarButton から CeltisRichTextToolbarButton へ登録先変更
                        el( CeltisRichTextToolbarButton,
                            { icon: idx.icon,
                              title: idx.title,
                              isActive: isActive,
                              onClick: () => onChange( toggleFormat(value, { type: type })),
                            }
                        )
                    )
                );
            },
        });
    }) 
    
}());

これでツールバーにスマイルアイコンの専用ボタンが追加されて、そこに マーカーとアンダーラインマーカーの2つのメニューが追加されるようになります

ちょっとコードが複雑になり、正直なところ私も理解できてません …  Gutenberg ソースコードの JSX を使って記述されているコードをベースにして、それを開発環境がなくても実行できるように変更して作成してみました

コードを理解するにはかなりの修行が必要なので プログラマー以外の方にはちょっと難しいですかね。私も JS が得意でないし、もっと手軽に JS を扱いたいのでなかなかムズい感じです (^_^;)

さらにいろいろ挑戦してみたいという方には、やはり開発環境を用意するのがおすすめです。 下記の create-block を使えば、 簡単に開発環境を構築できるようになったのでそこから始めるのが良いかもしれません

@wordpress/create-block | Block Editor Handbook | WordPress Developer Resources
Create Block is an officially supported way to create blocks for registering a block for a WordPress plugin. It offers a modern build setup…

以上、リッチテキストツールバーに新たにドロップダウンメニューボタンを追加する方法を紹介いたしました


まとめ記事紹介

go-to-top