[WordPress] Gutenbergの3つのレンダリング: 静的ブロックと動的ブロック、そしてクライアントサイドレンダリング

本記事は [WordPress Advent Calendar](https://qiita.com/advent-calendar/2017/wordpress) の15日目です。12月の初め頃はいくつか空きがありましたが、無事全部埋まって良かったです！

本記事では、Gutenbergで実用的なCustom Block Type（独自のブロック型）を作るための第一歩として、Gutenbergにおける3つのレンダリングについて紹介します。

なお、本記事のサンプルコードは下記リポジトリで公開しています。
https://github.com/ryo-utsunomiya/my-gutenberg-ext

## 静的ブロックと動的ブロック

Gutenbergのブロックには、二つの種類があります。

一つは「静的ブロック(Static Block)」で、これはエディタで保存した際にコンテンツが決まります。通常の記事データはこちらです。

もう一つが「動的ブロック(Dynamic Block)」です。これはサーバサイドでレンダリングされます。サーバサイドレンダリングというと聞き慣れないかもしれませんが、要はPHPで処理されるということで、ショートコードと同じです。Gutenbergの動的ブロックは、**クライアントサイドレンダリングではありません**。

では、Gutenbergでクライアントサイドレンダリングはできないのかというと、そんなことはありません。実際、ソーシャルウィジェット等はJavaScriptを使ってクライアントサイドレンダリングしています。あくまで、Gutenberg自身に機能がないだけで、その気になればJavaScriptを使ってクライアントサイドレンダリングを行うことは可能です。

## サンプルコード

本記事では、 [[WordPress] はじめてのGutenberg Custom Block Type](https://qiita.com/ryo511/items/d729f6f9695518edc5fa) でセットアップした開発環境を使用して、3つのレンダリングのサンプルコードを作成します。

いずれも現在時刻を描画するブロックですが、レンダリングされるタイミングが異なります。

- StaticClock
- SSRClock(Server Side Rendering Clockの略)
- CSRClock(Client Side Rendering Clockの略)

### 静的ブロック

はじめに、最もシンプルな静的ブロックからいきましょう。実装上特筆すべきことはありません。

```block.js
const { registerBlockType } = wp.blocks;

const staticNow = new Date().toISOString();

registerBlockType('my-gutenberg-ext/static-clock', {
    title: 'Static CLock',
    icon: 'universal-access-alt',
    category: 'layout',
    edit: () => <div>Now: {staticNow}</div>,
    save: () => <div>Now: {staticNow}</div>,
});
```

静的ブロックは、`save`関数が実行されるタイミングで値が保存されます。その後に値の変更はありません。

<img width="702" alt="Screen Shot 2017-12-14 at 22.58.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/33450/2108784e-ea33-18bd-4821-8f18cbd29b1f.png">

### 動的ブロック

動的ブロックには重要なお約束があります。それは、`save`関数では`null`を返すことです。こうすると、レンダリングはサーバサイドで行われます。

```block.js
registerBlockType('my-gutenberg-ext/ssr-clock', {
    title: 'SSR Clock',
    icon: 'universal-access-alt',
    category: 'layout',
    edit: () => <div>Now: #SSR#</div>,
    save: () => null,
});
```

`edit`関数では仮の値を表示しておきます。

<img width="690" alt="Screen Shot 2017-12-14 at 23.03.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/33450/55e94680-aa0e-49ab-e288-76f90c616236.png">


次にサーバサイドの処理を実装します。

```my-gutenberg-ext.php
function ssr_clock()
{
    $now = date(DateTime::ISO8601);
    return "<div>Now: {$now}</div>";
}


register_block_type('my-gutenberg-ext/ssr-clock', array(
    'render_callback' => 'ssr_clock',
));
```

ポイントは、`register_block_type`関数を使用し、第2引数のオプションの中で'render_callback'にサーバサイドレンダリング用の関数を登録することです。

これで、現在時刻がサーバサイドでレンダリングされるようになりました。サーバサイドレンダリングなので、リロードするたびに値が変わります。

<img width="237" alt="Screen Shot 2017-12-14 at 23.04.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/33450/7ce20de0-a35c-1dd7-5e23-8021f9bacecd.png">

### クライアントサイドレンダリング

最後に、クライアントサイドで動作する現在時刻表示ブロックを作りましょう。JavaScriptで描画対象の目星をつけやすいよう、描画したい場所にspan要素を置いてクラスをつけています(JSXではclassではなくclassNameな点に注意)。

```block.js
registerBlockType('my-gutenberg-ext/csr-clock', {
    title: 'CSR Clock',
    icon: 'universal-access-alt',
    category: 'layout',
    edit: () => <div>Now: #CSR#</div>,
    save: () => <div>Now: <span className="clock">#CSR#</span></div>,
});
```

次に、クライアントサイドのプログラムを実装します。

```clock.js
const tick = () => {
    const clocks = Array.from(document.getElementsByClassName('clock'));
    const now = new Date().toISOString();
    clocks.forEach(clock => clock.innerHTML = now);
};

window.addEventListener('DOMContentLoaded', tick);
setInterval(tick, 1000);

```

ここでは、1秒に1回`clock`というクラスのついた要素を探して、その中身を現在時刻で書き換えています。今度は、記事上でリアルタイムに時刻が描画されるようになります。

最後に、実装したJavaScriptを記事ページでも呼び出されるようにしましょう。Gutenbergで、エディタ画面と生地画面の両方で使用したいアセットは、`enqueue_block_assets`アクションで読み込みます。

```my-gutenberg-ext.php
function my_gutenberg_ext_enque_block_assets()
{
    wp_enqueue_script(
        'my-gutenberg-ext-frontend',
        plugins_url('clock.js', __FILE__),
        array('wp-blocks')
    );
}

add_action('enqueue_block_assets', 'my_gutenberg_ext_enque_block_assets');
```

これで、クライアントサイドレンダリングされるブロックが実装できました。

<img width="256" alt="Screen Shot 2017-12-14 at 23.20.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/33450/bca445bf-e498-929d-2ee6-bedb63d82cd4.png">

## まとめ

ここまで、Gutenbergにおけるレンダリング方法について見てきました。これらのうち、主に使うのは静的ブロックと動的ブロックとなるでしょう。

さまざまなチャネルから閲覧されるというブログの性質を考えると、クライアントサイドレンダリングで提供するのは付加的なコンテンツに限られると思います（仮にJavaScriptが動かないと記事が見られないとすると、RSSリーダーなどで読めなくなってしまいます）。