自己紹介

  • 宇都宮 諒(うつのみや りょう)​
  • 株式会社 一休 宿泊事業本部
  • 職種は「フロントエンドエンジニア」
  • 主なお仕事
  • ​WordPress歴
    • ​ユーザとして4年くらい
    • 開発者として1年くらい
  • ​Twitter: @ryo511
  • 個人ブログ( https://ryo511.info/ )

Agenda

  • Gutenbergはどういう技術で成り立っているのか
  • Gutenbergを拡張する(プラグインを作る)ためにはどういう技術が必要か

第1部

Gutenbergの

技術的な成り立ち

Gutenbergの成分表示

  • GutenbergはWordPressプラグイン
  • 主要成分はJavaScript
  • PHPもそれなりに

JavaScript(=ECMAScript)

  • Webブラウザ上で動作するプログラミング言語
  • JavaScriptの仕様はECMA Internationalという団体で策定されている
  • この仕様をECMAScriptと呼ぶ
  • 従来はES 3、ES 5のようなバージョン番号が使われていた
  • 2015年のES 6以降は毎年新バージョンが出るようになったため、発表年で呼ばれるように
  • 最新の仕様はES 2018

ECMAScriptのブラウザ対応

  • ECMAScriptの仕様化には、ブラウザでの実装状況も考慮される
    
  • ES 2018の主要機能は、2018年現在の主要なブラウザの最新版では動作する
  • ただし、IE 11はES 5で更新が止まっている

JavaScriptライブラリとnpm

  • Gutenbergでは、JavaScriptのライブラリ管理にはnpm(Node Package Manager)を使用している
    • PHPでいうところのComposer
  • npmはJavaScriptライブラリ管理のデファクトスタンダード
  • npmでは、依存しているライブラリをpackage.jsonというファイルに列挙する
  • package.jsonを見ることで、Gutenbergがどのようなライブラリを使っているかわかる

Gutenbergのpackage.json

  • dependencies(動作に必要なライブラリ)と、devDependencies(開発に必要なライブラリ)に分かれる
    
  • dependencies
    • React.js
    • jQuery
    • その他、@wordpress 系のライブラリ群
  • devDependencies
    • Babel
    • webpack
    • その他沢山

React.js

  • Facebookが開発した、リッチなUIを開発するためのJavaScriptライブラリ
  • 現在最も人気のあるJavaScriptライブラリの1つ
    • npmでは2017年に5900万回ダウンロードされた
    • 参考値:jQuery 4600万、Angular 1100万、Vue.js 800万
  • GutenbergのUIはReact.jsで作られている

React.jsはコンポーネント指向

  • React.jsは、リッチな=複雑なUIを、効率よく開発するためのライブラリ
  • Reactでは、コードを「コンポーネント」という単位で管理する
  • コンポーネントは、振る舞いと見た目を併せ持つ
  • Gutenbergでは、それぞれの「ブロック」が、Reactコンポーネントとして実装されている

React.jsのサンプルコード(1)

// ES2015のclass構文
class HelloMessage extends React.Component {
  render() {
    return (
      <div>
        Hello {this.props.name}
      </div>
    );
  }
}

最大の特徴は、JavaScriptの中にHTMLを書くこと

React.jsのサンプルコード(2)

// app というidを持つ要素に
// Reactアプリケーションを描画
ReactDOM.render(
  <HelloMessage name="World" />,
  document.getElementById("app")
);

// ↑の出力は以下のようなHTMLになる
<div>Hello World!</div>

JSX

function Hello(name) {
  // JavaScript関数の戻り値にHTMLを書く
  // 変数の埋め込みや関数呼び出しも可能
  return <div>{greeting(name)}</div>
}
  • JSXは、HTMLを直接書けるという点を除き、普通のJavaScriptと同じ
    
  • React.jsは、JSXによって高い表現力を実現している
  • しかし、JSXはブラウザでそのまま実行できるコードではない…

Babel

  • JavaScriptトランスパイラ
    
  • JSX => JavaScriptの変換のほか、新しいバージョンのJavaScript(ES2018等)を、古いバージョンのJavaScript(ES5)に変換することもできる
  • React.jsを使った開発では、ほぼ必須のソフトウェア
  • もちろん、Gutenbergでも使っている

JSXトランスパイル

// ESNext + JSX
const hw = <h1>Hello World</h1>;

// ES5(React)
var hw = React.createElement("h1", null,
  "Hello World");

// ES5(Gutenberg)
var hw = wp.element.createElement("h1", null,
  "Hello World");
  • JSXのHTMLタグは、React.createElement() の呼び出しと同じ
  • GutenbergはReact.createElement() をラップした独自メソッドを用意している

createElementを手書きする?

// JSX
<div className="container">
    <h1>Header1</h1>
    <p>Paragraph</p>
</div>

// ES5(記法が煩雑なので非推奨)
var el = wp.element.createElement;
el(
    'div',
    { className: 'container' },
    [
        el( 'h1', null, 'Header1' ),
        el( 'p', null, 'Paragraph' ),
    ],
);

Babelとセットで使う、

webpackというものがあると

聞いたんだけど… 🤔

webpack

  • webpackは、ES 2015のモジュールシステムを、レガシーブラウザ(IE 11等)でも動くようにするためのツール
  • Babelのようなトランスパイラとセットで使うことが多い
  • Gutenbergでもwebpackを使っている

モジュールシステム(ES2015)

  • jsファイルの外側から、ライブラリ等を読み込んで使用できるようにするための構文
    
  • import/exportというキーワードを使う
    • importはPHPでいうところのrequire
  • モダンブラウザ(Chrome, Safari, Firefox, Edge等)では動く
  • IE 11では動かないので、webpackを使って動作する形に変換する必要がある

モジュールバンドラ

  • webpackは、複数のjsファイルを1つのjsファイルにまとめる(バンドルする)
  • これによって、モジュールシステム非対応ブラウザでも、グローバル変数を介しないモジュール読み込みが実現できる

React開発には

Flux(Redux)というものを

使うと聞いたんだけど 👀

Flux(Redux)は必須ではない

  • Fluxは、複雑な状態を持つUIをメンテナブルに構築するためのアーキテクチャ
  • Reduxは、Fluxアーキテクチャを実装するためのライブラリの1つ
  • GutenbergはReduxを使っている
    • wp.dataがRedux APIのラッパー
  • Gutenbergプラグインは、Reduxは使わなくても開発できる

ここまでのおさらい

  • GutenbergはWordPressプラグインとして実装され、
  • npmを使ってライブラリを管理している
  • React.jsを使ってリッチなUIを実現している
  • Babelを使ってReactのJSXをブラウザで動くコードに変換している
  • webpackを使ってモジュールシステムがIE11でも動くようにしている

ところで、

Babelとかwebpackとか、

絶対に覚えないとダメ? 😨

最低限必要なのはReactだけ

  • webpack + Babelのビルドの仕組み作りはそれなりに複雑で、学習コストがかかる
    
  • しかし、開発効率のためにはJSXを使えた方がよい…
  • create-guten-block等、Gutenbergの開発環境をセットアップしてくれるツールが出てきている。初めはツールの助けを借りて、徐々に自分でも設定できるようにしていけばOK

第2部

Gutenbergのプラグイン開発

Gutenbergの基本はブロック

  • 記事の編集に使用する、再利用可能な部品

GutenbergのブロックAPI

  • 自分で定義したブロックを登録し、Gutenberg
    で利用可能にできる
  • 段落(paragraph)や画像(image)のようなコアブロックも、ブロックAPIを利用している
  • コアブロックは packages/block-library の下にあるので、一度は覗いてみるのをおすすめ

ブロックの登録

import HelloBlock from './HelloBlock';

wp.blocks.registerBlockType('my-block/hello', {
  // ブロックがもつメタデータを定義
  attributes: {},
  // ブロックの初回表示・編集時の動作を定義
  edit( { attributes, setAttributes } ) {
    return (
      <HelloBlock
        attributes={ attributes }
        setAttributes={ setAttributes }
      />
    );
  },
  // ブロックを保存する際の動作を定義
  save( { attributes } ) {},
});

ブロックはReactで作る

// GutenbergではReactという
// グローバル変数が定義されている

class HelloBlock extends React.Component {
  render() {
    const { name } = this.props.attributes;
    return <div>{ name }</div>;
  }
}

export default HelloBlock;
  • たとえば、コアの段落ブロックはParagraphBlockというReactコンポーネントとして実装されている

記事データの保存形式(1)

  • WordPressの記事データはwp_postsテーブルのpost_contentというカラムに保存される
    
  • クラシックエディタでは、保存されるのはHTML文字列
  • Gutenbergでも、保存先や保存形式は同じ
  • ただし、Gutenbergの場合、メタデータをコメントに埋め込む

記事データの保存形式(2)

<!-- wp:core/heading -->
<h2>What is Gutenberg?</h2>
<!-- /wp:core/heading -->

<!-- wp:core/cover-image {"url":"http://localhost:8888/wp-content/uploads/2017/12/Screen-Shot-2017-12-06-at-23.34.27.png","id":45} -->
<section class="wp-block-cover-image has-background-dim" style="background-image:url(http://localhost:8888/wp-content/uploads/2017/12/Screen-Shot-2017-12-06-at-23.34.27.png)">
</section>
<!-- /wp:core/cover-image -->

<!-- wp:core/paragraph -->
<p>Gutenberg is a new UX of WordPress editor.</p>
<!-- /wp:core/paragraph -->

Gutenbergブロックのメタデータは

HTMLコメントの中にJSON形式で埋め込まれる

記事データの保存形式(3)

<h2>What is Gutenberg?</h2>
<section class="wp-block-cover-image has-background-dim" style="background-image:url(http://localhost:8888/wp-content/uploads/2017/12/Screen-Shot-2017-12-06-at-23.34.27.png)">
</section>
<p>Gutenberg is a new UX of WordPress editor.</p>
  • 記事データとして(the_post()などで)出力されるHTMLからは、メタデータ(コメント)は取り除かれる
  • 記事のレンダリングはサーバサイド(PHP)で行われる。Reactは記事のレンダリングには使わない。

ブロックのライフサイクル

  1. edit() で初期状態を出力(保存されたコンテンツを編集する際は、以前の状態の復元)
  2. ユーザがコンテンツを編集する
  3. save() の結果をデータベースに保存

Attributes API

  • Gutenbergのブロックのメタデータのことをattributesと呼ぶ
    • 例:段落ブロックの文字サイズ等
  • ユーザがブロックに行った設定を反映するには、edit()の中でsetAttributes()メソッドを使用する
  • save() の中でattributesを参照して、最終的に保存するコンテンツを決定する
  • どのようなattributesを定義して、保存するか、がGutenbergのブロック開発のキモ

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

  • ブロックには、データベースへの保存時に内容が確定する静的ブロックと、サーバサイドでの処理を経て最終的な内容が確定する動的ブロックの2種類がある
  • 段落、画像等、主要なブロックは静的ブロック
  • Twitter等の埋め込みブロックは多くが動的ブロック
  • 埋め込みブロックの中には、Twitter等、描画に独自のJavaScriptを使用するブロックも多い

Q. プラグインが提供するブロックを使った後、そのプラグインをアンインストールしたらどうなるか?

A. クラシックブロックになる

  • 未知のブロックはクラシックブロックとして認識される
  • クラシックブロックはただのHTML
  • 静的ブロックはクラシックブロックになっても変わらず表示できる
  • 動的ブロックや、JavaScriptを伴うブロックは、表示がおかしくなる可能性あり

Gutenbergプラグインの構造

  • 通常のWordPressプラグインと同じ
  • enqueue_block_editor_assets アクションでブロックのJSを読み込む
<?php
add_action(
  'enqueue_block_editor_assets',
  function() {
    wp_enqueue_script(
      'my-block',
      plugins_url( 'build/index.js', __FILE__ ),
      array( 'wp-blocks', 'wp-element' )
    );
  }
);

まとめ

  • Gutenbergは様々なJavaScriptライブラリによって成り立っている
  • React.jsを作った、モダンなJavaScriptアプリケーションとして実装されている
  • モダンなWebフロントエンドの技術を身につけることが、Gutenberg対応プラグイン開発の基盤になる

Learn JavaScript, deeply"

- Matt Mullenweg, a founder of WordPress

参考文献

Gutenberg解体新書

By Ryo Utsunomiya

Gutenberg解体新書

WordCamp Tokyo 2018セッションスライド

  • 5,142