Gutenberg用備考ブロックを作る

前回に引き続き Gutenberg のブロックサンプルを作っていきたいと思います。今回は編集可能な備考ブロックを作ります。前回作ったただ文字を表示するブロックに比べれば多少使い道はあるでしょう。

前回は WP-CLI を使ってひな形を作りましたが、今回はスクラッチで作っていきます。ソースコードをGitLabにまとめてあるのでよかったらご覧ください。

プラグインの作成

まずはプラグインの作成からです。名前はなんでもいいですが今回は プラグイン名をmy-note-plugin 、ブロック名を note-block とします。

wp-content/plugins に my-note-plugin フォルダを作って、

$ cd wp-content/plugins
$ mkdir my-note-plugin

その中に my-note-plugin.php を作って、

$ cd my-note-plugin
$ vi my-note-plugin.php

中身はこんな感じでいいでしょう。

<?php
/**
 * Plugin Name:     My Note Plugin
 * Version:         0.1
 */

ここまでやると WordPress のプラグイン設定画面に作成したプラグインが表示されるので「有効化」します。


HTMLとCSSを作成

ブロックの作成に取り掛かる前に完成形のHTMLとCSSを作ります。これはまだ保存する必要はないですが、ブロックと同時に作るとぐちゃぐちゃになってくるので先に作ってしまいます。

HTMLはこんな感じ

<div class="wp-block-my-note-plugin-note-block">
  <p class="wp-block-my-note-plugin-note-block__heading">Note</p>
  <div class="wp-block-my-note-plugin-note-block__content">
    <p>備考本文</p>
    <p>備考本文</p>
  </div>
</div>

CSSはこんな感じ

.wp-block-my-note-plugin-note-block {
  background-color: #e8f2f9;
  border: solid 1px #63a4d2;
  border-radius: 3px;
  font-size: 14px;
  margin-bottom: 16px;
}

.wp-block-my-note-plugin-note-block__heading {
  background-color: #63a4d2;
  color: white;
  font-weight: bold;
  margin: 0;
  padding: 3px 10px;
}

.wp-block-my-note-plugin-note-block__content {
  padding: 8px 10px;
}

.wp-block-my-note-plugin-note-block__content p {
  margin: 0 0 5px;
}

.wp-block-my-note-plugin-note-block__content p:last-child {
  margin: 0;
}

完成形はこんな感じです。

ブロックには自動的に wp-block-プラグイン名-ブロック名 というクラスが割り当てられるため、それを元にクラス名、スタイルを付与しています。


CSSファイルとJavaScriptファイルを作成

ブロックの作成に入ります。まずは必要なファイルを作りましょう。先ほど作った my-note-plugin ディレクトリに note-block ディレクトリを作って、

$ cd my-note-plugin
$ mkdir note-block

style.css を作って、先ほどのCSSをそのまま保存します。

もう一つ index.js も作ります。ブロックの処理は基本的にこのファイルに書いていきます。

registerBlockType関数でブロック登録

ブロックは registerBlockType 関数で登録できます。

( function ( wp ) {
  var el = wp.element.createElement;
  var name = 'wp-block-my-note-plugin-note-block';

  wp.blocks.registerBlockType( 'my-note-plugin/note-block', {
    title: '備考ブロック',
    category: 'common',

    attributes: {
      heading: {
        type: 'string',
        source: 'children',
        selector: 'p.' + name + '__heading',
        default: 'Note'
      },
      content: {
        type: 'array',
        source: 'children',
        selector: 'p.' + name + '__content'
      }
    },
    
    edit: createEditElement,
    save: createSaveElement
  } );

} )( window.wp );

1行目と27行目はグローバル環境を汚さないための記述です。

registerBlockType 関数の第一引数には プラグイン名/ブロック名 を指定します。

第二引数にはブロックの情報を指定します。title はブロックの表示名。category はブロックのカテゴリで、Gutenbergエディタではブロックがカテゴリごとに表示されるのでその時使われます。attributes は一言で説明するのが難しいので興味があればこちらの記事を見てください。edit と save はそれぞれエディタ画面と実際の表示画面用にReact要素を出力する関数で、これから実装していきます。

edit関数とsave関数の実装

まずは edit 関数。

function createEditElement( props ) {
  return el(
    'div', {
      className: name
    }, [
      el(
        wp.editor.RichText, {
          tagName: 'p',
          className: name + '__heading',
          value: props.attributes.heading,
          onChange: function( heading ) {
            props.setAttributes( { heading: heading } );
          }
        }
      ),
      el(
        wp.editor.RichText, {
          tagName: 'div',
          className: name + '__content',
          value: props.attributes.content,
          multiline: 'p',
          onChange: function( content ) {
            props.setAttributes( { content: content } );
          }
        }
      )
    ]
  );
}

編集可能フィールドを作るには wp.editor.RichText コンポーネントを使います。今回はタイトルと本文の両方を編集できるようにしたいので2つの RichText を使っています。

ここで使用している el 関数は実際は wp.element.createElement 関数で、さらに言えば React の createElement 関数とほぼ一緒で、React要素を返しています。

Reactでは createElement 関数はほぼ使わず JSX で記述することが多いので見る人が見れば常軌を逸した書き方になっています。JSXを使った書き方は別の記事にまとめているのでよければそちらもご覧ください。

次に save 関数。

function createSaveElement( props ) {
  return el(
    'div', {
    }, [
      el(
        wp.editor.RichText.Content, {
          tagName: 'p',
          className: name + '__heading',
          value: props.attributes.heading
        }
      ),
      el(
        wp.editor.RichText.Content, {
          tagName: 'div',
          className: name + '__content',
          value: props.attributes.content
        }
      )
    ]
  );
}

edit 関数と似ていますが、save 関数では RichText の中身を表示するために wp.editor.RichText.Content を使用しています。イベントハンドラなどが必要ないのでコード量も少なめです。

最終的に index.js は以下のようになります。

( function ( wp ) {
    var el = wp.element.createElement;
    var name = 'wp-block-my-note-plugin-note-block';

  function createEditElement( props ) {
    return el(
      'div', {
        className: name
      }, [
        el(
          wp.editor.RichText, {
            tagName: 'p',
            className: name + '__heading',
            value: props.attributes.heading,
            onChange: function( heading ) {
              props.setAttributes( { heading: heading } );
            }
          }
        ),
        el(
          wp.editor.RichText, {
            tagName: 'div',
            className: name + '__content',
            value: props.attributes.content,
            multiline: 'p',
            onChange: function( content ) {
              props.setAttributes( { content: content } );
            }
          }
        )
      ]
    );
  }

  function createSaveElement( props ) {
    return el(
      'div', {
      }, [
        el(
          wp.editor.RichText.Content, {
            tagName: 'p',
            className: name + '__heading',
            value: props.attributes.heading
          }
        ),
        el(
          wp.editor.RichText.Content, {
            tagName: 'div',
            className: name + '__content',
            value: props.attributes.content
          }
        )
      ]
    );
  }

  wp.blocks.registerBlockType( 'my-note-plugin/note-block', {
    title: '備考ブロック',
    category: 'common',

    attributes: {
      heading: {
        type: 'string',
        source: 'children',
        selector: 'p.' + name + '__heading',
        default: 'Note'
      },
      content: {
        type: 'array',
        source: 'children',
        selector: 'p.' + name + '__content'
      }
    },
    
    edit: createEditElement,
    save: createSaveElement
  } );

} )( window.wp );

PHPの作成

PHP側の設定を行います。PHP側ではスクリプトファイルとスタイルファイルの登録と、ブロックの登録の2つを行います。処理は init にフックさせます。

my-note-plugin.php を編集します。

<?php
/**
 * Plugin Name:     My Note Plugin
 * Version:         0.1
 */

add_action( 'init', function() {
	if ( ! function_exists( 'register_block_type' ) ) {
		return;
	}
	$dir = dirname( __FILE__ );

	$index_js = 'note-block/index.js';
	wp_register_script(
		'note-block-block-editor',
		plugins_url( $index_js, __FILE__ ),
		array(
			'wp-blocks',
			'wp-element',
		),
		filemtime( "$dir/$index_js" )
	);

	$style_css = 'note-block/style.css';
	wp_register_style(
		'note-block-block',
		plugins_url( $style_css, __FILE__ ),
		array(),
		filemtime( "$dir/$style_css" )
	);

	register_block_type( 'my-note-plugin/note-block', array(
		'editor_script' => 'note-block-block-editor',
		'style'         => 'note-block-block',
	) );
} );

wp_register_script と wp_register_style でスクリプトファイルとスタイルファイルの登録、register_block_type でブロックにスクリプトとスタイルを紐づけています。


Gutenberg エディタで確認

ここまで行うと、画像のように Gutenberg エディタからブロックが追加できるようになっているはずです。

タイトルと本文、ともに編集できます。

記事表示画面でもちゃんと表示できます。


エディタ限定のスタイル

エディタ上ではタイトル部分の文字色が黒くなっていますが、これはGutenbergエディタ内の .edit-post-visual-editor p に対してスタイルが設定されているためです。

これを解決するためには style.css と同じ階層に editor.css を作成し、以下の内容を記述します。

.edit-post-visual-editor .wp-block-my-note-plugin-note-block__heading {
  color: white;
}

note-block.php にも以下の記述を追加し、

$editor_css = 'note-block/editor.css';
wp_register_style(
	'note-block-block-editor',
	plugins_url( $editor_css, __FILE__ ),
	array(),
	filemtime( "$dir/$editor_css" )
);

register_block_type を修正します。

register_block_type( 'my-note-plugin/note-block', array(
	'editor_script' => 'note-block-block-editor',
	'editor_style'  => 'note-block-block-editor',
	'style'         => 'note-block-block',
) );

白くなりました。


おわり

全体を理解しようと思ってスクラッチで書いて見ましたが、結構使い回しがきく部分が多いので WP-CLI のひな形から作った方が早いかもしれません。

あと今回は説明のためにエディタ用CSSファイルを作りましたが、この程度の差であれば style.css に全てひっくるめてもいいと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です