Before Gutenberg – ブロックタイプの登録

本稿ではいよいよGutenbergのブロックタイプについて学んでいこう。Gutenbergではカスタムブロックタイプを登録することができる。このブロックタイプにはいくつか種類があるのだが、まずは一番簡単な「見栄えに関する設定項目だけが存在するブロック」を作ってみよう。

なお、以前の記事ではじめてのカスタムブロックというものがあるのだが、重複するところが多いことをお断りしておく。とはいえ、半年以上前の記事であることと、JSXを採用している点を鑑みると、本稿から学ぶことも多いだろう。

成果物

成果物としては、次のようなアラートボックスを作成することを目指す。アラートボックスには次の2つの要素が存在する。

  1. スタイル。success, info, warning, dangerの4種類がある。
  2. メッセージ。これはリッチテキスト(HTML)として編集可能で、strongタグとaタグなどを挿入することができる。
アラートボックスの最終的な見栄え。

なぜアラートボックスから始めるかというと、動的な要素が絡む場合、話は少し変わるからだ。「Before Gutenberg – ぼくのショートコードを守って」で紹介したような、ユーザーを指定する方法だと、難易度が上がるのである。

ブロックの登録

さて、まずはカスタムブロックcapitalp-block/alertを登録しよう。ブロック名はスラッシュで区切られた名前空間をつけるのがマナーのようだ。この作業はPHPで行うので、適当なプラグインを作成してregister_block_typeを呼び出してほしい。

/**
 * Register scripts, css, and block.
 */
add_action( 'init', function() {
  $version  = '1.0.0';
  $base_url = plugin_dir_url( __FILE__ );
  // Register alert's script.
  wp_register_script(
    'capital-block-alert',
    $base_url . 'assets/js/alert.js',
    [ 'wp-blocks', 'wp-element' ],
    $version,
    true
  );
  // Register block style.
  wp_register_style(
    'capital-block-alert',
    $base_url . 'assets/css/alert.css',
    [],
    $version
  );
  // Register block if gutenberg exists.
  if ( defined( 'GUTENBERG_VERSION' ) ) {
    register_block_type( 'capital-block/alert', [
      'editor_script'   => 'capital-block-alert',
      'editor_style'    => 'capital-block-alert',
    ] );
  }
} );

editor_scripteditor_styleがそれぞれJSとCSSを読み込んでくれる。なお、wp_regiser_sciprtで依存関係に指定しているwp-blockswp-elementは前者がブロック用のユーティリティ、後者がReactのエイリアスである。

CSSの内容については割愛する。alertおよびalert-successといったBootstrap方式のクラスを指定すると上で紹介したようなアラートボックスになると考えてほしい。

それでは、肝心のJSの内容に入ろう。一気に貼り付けるので、順を追って中身を説明していく。ES6の文法に不安がある人は、前回の記事を復習しておいてほしい。

const { registerBlockType } = wp.blocks;
const { RichText }          = wp.editor;

registerBlockType( 'capital-block/alert', {

  title: 'Alert',

  icon: 'info',

  category: 'widgets',

  attributes: {
    style: {
      type: 'string',
      default: 'info'
    },
    content: {
      type: 'array',
      source: 'children',
      selector: 'p',
    },
  },

  edit( { attributes, setAttributes } ) {

    function onChange(event){
      setAttributes({style: event.target.value});
    }

    function onChangeContent(newContent){
      setAttributes( { content: newContent } );
    }

    return (
      <div className={`alert alert-${attributes.style}`}>
        <select onChange={onChange}>
          <option value={'success'}>Success</option>
          <option value={'info'}>Info</option>
          <option value={'warning'}>Warning</option>
          <option value={'danger'}>Danger</option>
        </select>
        <RichText
          tagName="p"
          onChange={ onChangeContent }
          value={ attributes.content }
        />
      </div>
    )
  },

  save( { attributes } ) {
    return (
      <div className=>
      </div>
      <RichText.Content
        tagName="p"
        value={ attributes.content }
      />
    );
  }
} );

まず最初のconstブロックは、利用するライブラリにわかりやすい名前をつけている。WordPressではwp名前空間にすべてのライブラリが格納されていくので、それを以前紹介した分割代入でエイリアス(別名)にしいてる。

const { registerBlockType } = wp.blocks;
const { RichText } = wp.editor;

続いて、registerBlockTypeメソッドを利用して、ブロックを登録している。さっきPHPで登録したから2回やらなくていいような気がするのだが、公式ドキュメントに書いてあるのだから仕方がない。次回以降で紹介するダイナミックブロックなどでは必要な処理になるのだろう。1番目にブロック名、2番目がオプションである。

registerBlockType( 'capital-block/alert', {} );

オプションの指定

さて、オプションのうち、簡単なものから見ていこう。

registerBlockType( 'capital-block/alert', {
  title: 'Alert',
  icon: 'info',
  category: 'widget',
} );

まず、titleはそのまま、ブロックの名前である。ここは多言語対応できるのだが、それは次回以降で紹介する。続いてiconであるが、これはdashiconsの接頭辞dashicons-を除いたものを指定する。dashiconsにないものを指定したい場合はどうするのかというと、インラインでSVGを指定する。マジかという感じである。そしてカテゴリー。これはドキュメントにあるもののほか、フィルターフックで拡張できるようだ。この3つを指定すると、次のようなUIとして表現される。

ブロックが追加されると、こんな感じに。Alertが見えるだろうか。

属性

さて、それでは難しい方のオプションに移ろう。まずはattriburesから。これはブロックの属性値として保存されるものだ。HTMLの一部(たとえば、pタグ内のテキスト)として表現される場合と、コメントとして保持される値(たとえばショートコードの回で説明したユーザーID)がある。前者の場合は次のように指定する。

{
  attributes: {
    content: {
      type: 'string',
      source: 'html',
      selector: 'p',
    }
  }
}

この場合、ブロック内のpタグの中身のHTMLがcontentだよ、ということになる。ここでsourceを指定しなかった場合、属性値はコメントに保存される。

内部的にはこのようにコメント内で保存される。"style": "warning"がそれ。

今回はstylecontentという2つの属性が必要なのでそのように登録した。

registerBlockType( 'capital-block/alert', {
  attributes: {
    style: {
      type: 'string',
      default: 'info'
    },
    content: {
      type: 'array',
      source: 'children',
      selector: 'p',
    },
  },
});

実は筆者もハマったのだが、contentの属性値がarrayになっているのに気づいただろうか。これはあとで紹介するビデオの中で触れているのだが、リッチテキスト(中でタグを利用可能なテキスト)の場合、「React.DOMの配列」と解釈されるため、配列にする必要があるらしい。rich-text, text, htmlなど色々試したが、複数のタグを利用する場合はarrayかつchildrenでなくてはならないようだ。

edit & save

それでは最難関であるeditsaveオプションへ移ろう。これはオプションというより、メソッドである。その名前とは異なり、editは編集用画面を描画するメソッド、saveは保存用のHTMLを描画するメソッドである。この2つが似通っていれば問題ないのだが、実際は少し異なる。それぞれ別にみていこう。

editメソッド

今回のアラートボックスはスタイルとコンテンツの2種類の属性を持つ。ちょっとかっこわるいのだが、スタイルはプルダウンで選択させ、コンテンツはリンクや強調を使うこともあると思われるのでリッチテキストとして編集できるようにしよう。

{
  edit( { attributes, setAttributes } ) {

    function onChange(event){
      setAttributes({style: event.target.value});
    }

    function onChangeContent(newContent){
      setAttributes( { content: newContent } );
    }

    return (
      <div className={`alert alert-${attributes.style}`}>
        <select onChange={onChange}>
          <option value={'success'}>Success</option>
          <option value={'info'}>Info</option>
          <option value={'warning'}>Warning</option>
          <option value={'danger'}>Danger</option>
        </select>
        <RichText
          tagName="p"
          onChange={ onChangeContent }
          value={ attributes.content }
        />
      </div>
    )
  },
}

まず、分割代入によって、ブロックのattributesと属性を変更するsetAttributesメソッドを引数にとる。Reactではコンポーネントのプロパティを変更するときに block.attribute = 'new_valeu' と指定するだけではUIへの変更が伝播されず、必ずメソッドを経由する必要がある。

続いてプルダウンの変更とリッチテキストの変更を検知するメソッドを2つ用意し、それぞれにsetAttributesを実行させる。

function onChange(event){
  setAttributes({style: event.target.value});
}
function onChangeContent(newContent){
  setAttributes( { content: newContent } );
}

それから、JSXをリターンすることで、UIの描画が完了する。<RichText/>という見慣れないタグはReactのコンポーネントで、Gutenbergに初めから備わっているものだ。これによってできる見栄えは次のようなものになる。

プルダウンがちょっとかっこ悪いのだが、致し方ない。

saveメソッド

ここでは保存すべきHTMLを描画する。もちろん、ショートコードで紹介したような、「ユーザーIDからアバターを表示する」といったことをしたければまた別の方法もあるのだが、今回は管理画面で作成したHTMLをそのままテーマ側でも表示してしまって問題ないように作っているので、editからプルダウンを除いたものを保存すればよいだろう。

{
  save({attributes}) {
    return (
      <div className={`alert alert-${attributes.style}`}>
        <RichText.Content
          tagName={'p'}
          value={attributes.content}/>
      </div>
    );
  },
}

editとの大きな違いとしては、RichTextRichText.Content になっていることぐらいだ。これにより、次のようなHTMLが保存されるようになる。

<!-- wp:capital-block/alert {"style":"warning"} -->
<div class="wp-block-capital-block-alert alert alert-warning"><p>はじめてのアラートです。<strong>強調</strong>も使えるし、リンクも使えます。</p></div>
<!-- /wp:capital-block/alert -->

CSSの読み込み

さて、以上でほとんど終わりなのだが、あとはCSSの読み込みだけだ、最初のPHPファイルにCSSの読み込み処理を書いて終わり。

// Load style.
add_action( 'wp_enqueue_scripts', function() {
	wp_enqueue_style( 'capital-block-alert' );
} );

同じCSSで済めばそれはそれで嬉しいのだが、実際のところ、Gutenbergでは各ブロックに強い詳細度でスタイルが当たってしまっており、今回の例でも「管理画面では文字が黒、公開側では文字が白」という状態になっている。これを解決するためのアイデアもなくはないのだが、それは次回以降に譲ろう。ともあれ、CSSの読み込みがうまくいくと、次のようになる。

こちらはちゃんと文字が白に。

とりあえず、以上でカスタムブロック道の入り口に立ったと言えるだろう。それでは、有料会員向けに、以下のコンテンツをお届けする。

  1. コーディング動画
  2. ソースコードの全体

続きの 4% を読み、添付されたファイルにアクセスするには、Gumroadでライセンスキーを取得してください!

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください