前回はシンプルなアラートボックスを作成したが、今回は外部要因によって動的に中身が変更されるダイナミックブロックに挑戦してみよう。
ダイナミックブロックとは?
PHPによる動的な生成を伴うものである。保存される内容=表示される内容でよいのなら以前のやり方でよいが、たとえば、「最新の投稿リスト」のようなものの場合、その内容は変わっていく。
今回は「x年y月のイベント一覧を表示するブロック」という想定をしよう。条件は次の通り。
- 沢山のイベントがカスタム投稿タイプ
event
として登録されている。 - 各イベントは開催日(
_event_date
)、会場の緯度(_lat
)および経度(_lng
)をカスタムフィールドに持つ。 - Gutenbergでブロックに年
year
および月month
を指定すると、その時期に開催されるイベントの一覧が出力される。
それでは、早速とりかかろう。今回表示するブロックのイメージは次の通り。
ブロックの登録
前回と同じく、まずは、必要なアセットとブロックをPHPから次のようにして登録する。時間の節約のため、CSSの内容はすでに完成しているものとする。
/** * Register event and block assets. */ add_action( 'init', function() { // Register CSS & JS. wp_register_style( 'capital-block-event', CAPITAL_BLOCK_ASSET_URL . 'assets/css/event.css', [], CAPITAL_BLOCK_VERSION ); wp_register_script( 'capital-block-event', CAPITAL_BLOCK_ASSET_URL . 'assets/js/event.js', [ 'wp-element', 'wp-blocks' ], CAPITAL_BLOCK_VERSION, true ); // Register block. if ( defined( 'GUTENBERG_VERSION' ) ) { register_block_type( 'capital-block/event', [ 'editor_style' => 'capital-block-event', 'editor_script' => 'capital-block-event', ] ); } } );
続いて、JSの中身を書いていこう。今回のダイナミックブロックでは、save
メソッドを定義しない。実際のレンダリングはPHPで行うからだ。edit
メソッドはとりあえず罫線(hr
)を出力しておこう。
const { registerBlockType } = wp.blocks; registerBlockType( 'capital-block/event', { title: 'Event', icon: 'calendar-alt', category: 'embed', attributes: { year: { type: 'integer', }, month: { type: 'integer', }, }, edit( {attributes, setAttributes} ) { return <hr /> }, save(){ return null; } } );
以上で、とりあえず罫線が表示されるブロックが出力されるはずである。
編集UIの作成
それでは、編集UIの作成をしよう。今回は年月を指定するプルダウンを作成する。
registerBlockType( 'capital-block/event', { edit( {attributes, setAttributes} ) { const years = []; for(let i = 0; i < 20; i++){ years.push( 2016 + i ); } const months = []; for(let i = 1; i <= 12; i++){ months.push(i); } return ( <div className='event-editor'> <select onChange={ (event) => { setAttributes({year: event.target.value}) } }> {years.map( (year) => { return ( <option value={year} selected={year == attributes.year}>{year}年</option> ) } )} </select> <select onChange={ (event) => { setAttributes({month: event.target.value}) } }> {months.map( (month) => { return ( <option value={month} selected={month == attributes.month}>{month}月</option> ) } )} </select> <hr/> </div> ); }, } );
ポイントとしては、Reactにはループの制御構文がないので、Array.map
を利用して反復処理を行っている点。詳細はReactでの配列ループ利用方法をおさらいするなどを参考にしてほしい。これで年月を選択して保存すると、実際に保存されるデータは次のようになる。
<!-- wp:capital-block/event {"year":"2018","month":"7"} /-->
さて、この記事を表示してみても何も表示されない。コメントしかないからだ。そこで、render_callback
を登録して、描画関数をPHPに書く。
register_block_type( 'capital-block/event', [ 'editor_style' => 'capital-block-event', 'editor_script' => 'capital-block-event', 'render_callback' => function( $attributes, $content = '' ) { $attributes = wp_parse_args( $attributes, [ 'year' => 0, 'month' => 0, ] ); return capital_block_render_event( $attributes['year'], $attributes['month'] ); }, ] );
今回は$year
と$month
を渡すと当該月のイベントリストを表示する自作関数capital_block_render_event
を利用している。ここまでで次のようにテーマ側できちんと表示されているはずだ。
テーマと管理画面での見栄えを一致させる
さて、現状のUIだと、年月を指定するたびにそれがどのような見栄えになるのかをプレビューしなければならない。そこで、PHPによる描画結果を管理画面でも見たいものだ。そのためのAPIがServerSideRender
である。
これはReactがREST APIを利用して、PHPによる描画結果を生成するものだ。JS側で早速この処理を書いてみよう。attributes
とブロック名を渡すだけで描画してくれる優れものだ。attributes
の変更も検知し、自動でUIを更新してくれる。
const { registerBlockType } = wp.blocks; const { ServerSideRender } = wp.components; registerBlockType( 'capital-block/event', { edit( {attributes, setAttributes} ) { // 中略 return ( <div className='event-editor'> // 中略 <hr/> <ServerSideRender block="capital-block/event" attributes={ attributes } /> </div> ); }, } );
ただし、これだけだとまだ動かない。PHP側にどのような属性を受け入れるのかを支持する必要がある。これはregister_block_type
関数で行うことができる。
register_block_type( 'capital-block/event', [ 'editor_style' => 'capital-block-event', 'editor_script' => 'capital-block-event', 'attributes' => [ 'year' => [ 'type' => 'integer', ], 'month' => [ 'type' => 'integer', ], ], 'render_callback' => function( $attributes, $content = '' ) { $attributes = wp_parse_args( $attributes, [ 'year' => 0, 'month' => 0, ] ); return capital_block_render_event( $attributes['year'], $attributes['month'] ); }, ] );
これでプルダウンを変更するたびイベントのリストが更新されるようになった。
まとめ
ダイナミックブロックによるサーバーサイドレンダリングはあくまでフォールバックであり、公式に推奨されない方法だそうだ。しかし、Shortcakeと同じく、WYSIWYGを提供する機能として便利なので、しばらくは使われることだろう。APIとJSをわけるコーディングより労力が少ないのも嬉しいポイントだ。
以下、有料会員向けにソースコード全体とコーディング動画を提供する。