Gutenbergのブロックエディターにテーマのスタイルを適用する方法

WordPress 5.0からGutenbergと呼ばれる新しいコンテンツエディターが実装され、従来使われてきたTinyMCEエディターと置き換わる形となります。

それに伴い、テーマの見た目やデザインを編集画面に再現するためのエディター用スタイル（[Editor Style](https://codex.wordpress.org/Editor_Style)）の仕様も変更となるので、その方法についてまとめてみました。

※以下、Gutenberg以前のエディターを「クラシックエディター（ビジュアルエディター）」、Gutenberg以降の新エディターを「ブロックエディター」と呼ぶことにします。

## 注意事項

- 一番の情報ソースである[Gutenberg Handbook](https://wordpress.org/gutenberg/handbook/extensibility/theme-support/)の記述も、本リリースを目前に控え日々アップデートされているようなので、2018年11月16日時点の最新情報としてお読みください。
- ブロックエディターでの実装方法については、次期デフォルトテーマである「[Twenty Nineteen](https://github.com/WordPress/twentynineteen)」を参考にしていますが、こちらのテーマも鋭意開発中であることを留意してもらえると助かります。

## Gutenberg以前（クラシックエディター）のやり方

`fonction.php`内で`add_editor_style`関数を実行して、エディター用のCSSを読み込みます。

※通常は`after_setup_theme`アクションフック内で実行します。

```php

if ( ! function_exists( 'twentynineteen_setup' ) ) :
    function twentynineteen_setup() {

        add_editor_style( 'style-editor.css' );

    }
endif;
add_action( 'after_setup_theme', 'twentynineteen_setup' );
```

すると、管理画面のビジュアルエディター部分に生成されているiframe内で（その中にさらにhtml要素が生成されています）、head要素の中に指定したCSSが外部ファイルとして読み込まれます。

![gutenberg-editor-style1.png](https://qiita-image-store.s3.amazonaws.com/0/91235/4677b79f-682e-6f62-ebfd-da3d594d301c.png)

これによってビジュアルエディター内では、指定したCSSが有効になるため、テーマと同様のスタイルを記述して適用させることができます。

そのため、エディター用スタイルとして特に変わった書き方をする必要はありませんが、例えばフロント側で`.entry-content`内だけにスタイルを適用している場合は、エディター全体を囲っている`.mce-content-body`というクラスに対しても同様のスタイルを当てる、などの手法が一般的です。

### 投稿本文の見出しに適用されたスタイルを、ビジュアルエディターにも適用した例

```css

.entry-content h1,
.mce-content-body h1 {
	border-bottom: 5px solid #429BBF;
	padding-bottom: .45rem;
	margin-bottom: 1rem;
	line-height: 1.4;
}

.entry-content h2,
.mce-content-body h2 {
	border-bottom: 1px solid #c2c1c1;
	padding-bottom: .45rem;
	margin-bottom: 1rem;
	line-height: 1.4;
}
```

## Gutenberg以降（ブロックエディター）のやり方

基本的なやり方はGuteberg以前と変わりませんが、従来は特に必要ないとされていた`add_theme_support`関数で`editor-style`を指定し、明示的にエディター用スタイルの機能をテーマに追加します。

これと`add_editor_style`関数を併用することで、初めてブロックエディター内でエディター用スタイルが有効になります。

```php

if ( ! function_exists( 'twentynineteen_setup' ) ) :
    function twentynineteen_setup() {

        add_theme_support( 'editor-styles' );
        add_editor_style( 'style-editor.css' );

    }
endif;
add_action( 'after_setup_theme', 'twentynineteen_setup' );
```

ブロックエディターではiframeは生成されないため、外部CSSとしては読み込まれませんが、その代りにbody閉じタグの直前にstyle要素が生成され、その中にエディター用スタイルが記述される形となります。

![gutenberg-editor-style2.png](https://qiita-image-store.s3.amazonaws.com/0/91235/d747e49f-3183-7bb8-38d7-43d706d9ad32.png)

さらにCSS内の各セレクターの直前に、ブロックエディター全体を囲っている`.editor-styles-wrapper`というクラスが自動的に挿入されるようになります。

![gutenberg-editor-style3.png](https://qiita-image-store.s3.amazonaws.com/0/91235/254b052c-ada5-d059-641c-8cc7954e55e5.png)

そのため、エディター用スタイルの中では、特にセレクターを意識せずに記述しても、ブロックエディター内にだけ適用される形になるため、その点は安心です。

※エディター用CSS内でセレクターに`body`と記述していた場合、それも自動的に`.editor-styles-wrapper`に置き換えてくれます。

### エディター用CSSの記述例

```css

body {
  font-size: 22px;
  font-family: "NonBreakingSpaceOverride", "Hoefler Text", "Baskerville Old Face", Garamond, "Times New Roman", serif;
  line-height: 1.8;
  color: #111;
}

p {
  font-size: 22px;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
```

### ブロックエディター上で変換されて、実際に読み込まれるCSS

```css

.editor-styles-wrapper {
  font-size: 22px;
  font-family: "NonBreakingSpaceOverride", "Hoefler Text", "Baskerville Old Face", Garamond, "Times New Roman", serif;
  line-height: 1.8;
  color: #111;
}

.editor-styles-wrapper p {
  font-size: 22px;
}

.editor-styles-wrapper h1,
.editor-styles-wrapper h2,
.editor-styles-wrapper h3,
.editor-styles-wrapper h4,
.editor-styles-wrapper h5,
.editor-styles-wrapper h6 {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
```

### 補足的なエディター用スタイルの読み込み

Gutenberg以降のブロックエディターでは、上記の`add_editor_style`によるやり方に加えて、`enqueue_block_editor_assets`というアクションフックを使ったCSSの読み込み方法もサポートされています。

こちらは、旧クラシックエディターで行われていたエディター用スタイルの仕様に近く、指定したCSSが管理画面のhead要素内に外部ファイルとして読み込まれる形となります。

```php

function twentynineteen_editor_customizer_styles() {

	wp_enqueue_style( 'twentynineteen-editor-customizer-styles', get_theme_file_uri( '/style-editor-customizer.css' ), false, '1.0', 'all' );

}
add_action( 'enqueue_block_editor_assets', 'twentynineteen_editor_customizer_styles' );
```

![gutenberg-editor-style5.png](https://qiita-image-store.s3.amazonaws.com/0/91235/70c7c691-84ca-fcc4-4a98-9ebfecdc5cb8.png)

ただし、この方法では`.editor-styles-wrapper`クラスを自動的に付与してくれたりはしないため、セレクターの書き方を工夫しないと管理画面全体のスタイルに影響してしまうので、注意が必要です。

特に`.editor-styles-wrapper`を付ける必要がないスタイルや、`.editor-styles-wrapper`を付けるとうまく効かないスタイルなどを指定する用途で、あくまで補助的に使用するのが良いと思われます。

Twenty Nineteenでは、html要素に付けられたlang属性ごとに、ブロックに指定するスタイルを切り替える目的で使用されているようです。

#### 補足的なエディター用スタイルの例

```css

/* Arabic */
html[lang="ar"] .wp-block *,
html[lang="ary"] .wp-block *,
html[lang="azb"] .wp-block *,
html[lang="ckb"] .wp-block *,
html[lang="fa-IR"] .wp-block *,
html[lang="haz"] .wp-block *,
html[lang="ps"] .wp-block * {
  font-family: Tahoma, Arial, sans-serif !important;
}
```

## まとめ

早くからGutenberg対応について書かれたTIPSの中では、`enqueue_block_editor_assets`を使ったやり方をメインで解説しているケースが多かったのですが、WordPress 5.0のリリースが近づくに連れて、エディター用スタイルの仕様も少しずつ変わって来たものと思われます。

次期デフォルトテーマであるTwenty Nineteenの実装を見れば分かる通り、今後は`add_editor_style`を用いた方法が主流になることは明白なので、テーマ制作者もそれに則った対応をするべきなのでしょう。

とはいえ、自動的に`.editor-styles-wrapper`でラップしてくれる機能があるため、管理画面への干渉を恐れる心配はなく、従来のエディター用スタイルと同じ手法でCSSを作成すれば良さそうです。

ただし、Gutenberg特有のブロック用スタイルなども多数必要となってくるため、それについてもTwenty Nineteenを始めとした、Gutenberg-readyなテーマをお手本にしながら対応することをお勧めします。

## 参考リンク

- [Theme Support – The new Gutenberg editing experience — WordPress](https://wordpress.org/gutenberg/handbook/extensibility/theme-support/)
- [関数リファレンス/add editor style \- WordPress Codex 日本語版](https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/add_editor_style)
- [WordPress/twentynineteen: Twenty Nineteen Default Theme](https://github.com/WordPress/twentynineteen)