Gutenberg Handbook 読書メモ (1) の続き。
Block
https://wordpress.org/gutenberg/handbook/blocks/
新しいブロック型を作るためのチュートリアル。
このチュートリアルのコードは下記GitHubリポジトリから入手できる。
https://github.com/WordPress/gutenberg-examples
なお、本記事のサンプルコードはESNextとJSXを使用しているが、Gutenbergのブロック機能はES5でも利用できる。
Writing Your First Block Type
https://wordpress.org/gutenberg/handbook/blocks/writing-your-first-block-type/
はじめに、固定されたメッセージを表示するブロック型を作成する。静的なコンテンツを含むブロックはJavaScriptでregisterBlockType
関数を使うだけで実装できる。この関数はブロックの青写真となり、エディタ上での表示、編集・保存時の動作等を定義する。
ブロックのスクリプトを追加(enque)する
ブロック型はJavaScriptで実装されるが、WordPressのenqueue_block_editor_assets
アクションを使ってスクリプトがエディタに読み込まれるようにする必要がある。このアクションはwp_enqueue_scripts
と似ているが、エディタのスクリプトとスタイルに限定される点に違いがある。
<?php
function gutenberg_boilerplate_enqueue_block_editor_assets() {
wp_enqueue_script(
'gutenberg-boilerplate-es5-step01',
plugins_url( 'step-01/block.js', __FILE__ ),
array( 'wp-blocks', 'wp-element' )
);
}
add_action( 'enqueue_block_editor_assets', 'gutenberg_boilerplate_enqueue_block_editor_assets' );
特に注意が必要なのは以下のように設定していること。
wp-blocks
は、ブロック型の登録と関連する関数の読み込みを行うwp-element
はWordPressのElement抽象化機能を使用する
ブロックの登録
スクリプトが登録されたので、次にブロックを実装する。
const { registerBlockType } = wp.blocks;
const blockStyle = { backgroundColor: '#900', color: '#fff', padding: '20px' };
registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-01', {
title: 'Hello World (Step 1)',
icon: 'universal-access-alt',
category: 'layout',
edit() {
return <p style={ blockStyle }>Hello editor.</p>;
},
save() {
return <p style={ blockStyle }>Hello saved content.</p>;
},
} );
ブロックを登録すると、エディタのinserterのダイアログで利用できるようになる。inserterではtitle, icon, categoryが利用される。アイコンは組み込みのアイコンから選ぶか、独自のsvg要素を指定する。
ブロック名は nemaspace/block-name
という構造である必要がある。
edit
とsave
関数は、エディタ画面でのレンダリングと保存後のレンダリングを定義する。
Applying Styles From a Stylesheet
https://wordpress.org/gutenberg/handbook/blocks/applying-styles-with-stylesheets/
↑のサンプルではインラインでスタイルを定義しているが、外部のスタイルシートにスタイルを定義して、これを読み込む方法もある。
エディタは、それぞれのブロック型に対して、独自のクラス名を自動的に生成する。このクラス名には、edit
とsave
関数のオブジェクト引数からアクセスできる。
const { registerBlockType } = wp.blocks;
registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-02', {
title: 'Hello World (Step 2)',
icon: 'universal-access-alt',
category: 'layout',
edit( { className } ) {
return <p className={ className }>Hello editor.</p>;
},
save( { className } ) {
return <p className={ className }>Hello saved content.</p>;
},
} );
クラス名は、ブロック名を元に生成される。
/* 対応するブロックは gutenberg-boilerplate-esnext/hello-world-step-02 */
.wp-block-gutenberg-boilerplate-es5-hello-world-step-02 {
color: green;
background: #cfc;
border: 2px solid #9c9;
padding: 20px;
}
エディタでのみ使用するブロックのアセットを登録(enque)する
enqueue_block_editor_assets
アクションを使うことでエディタでのみ使用するスタイルを登録できる。
<?php
function gutenberg_boilerplate_enqueue_block_editor_assets() {
wp_enqueue_script(
'gutenberg-boilerplate-es5-step02',
plugins_url( 'step-02/block.js', __FILE__ ),
array( 'wp-blocks', 'wp-element' )
);
wp_enqueue_style(
'gutenberg-boilerplate-es5-step02-editor',
plugins_url( 'step-02/editor.css', __FILE__ ),
array( 'wp-edit-blocks' ),
filemtime( plugin_dir_path( __FILE__ ) . 'step-02/editor.css' )
);
}
add_action( 'enqueue_block_editor_assets', 'gutenberg_boilerplate_enqueue_block_editor_assets' );
エディタとフロントエンドで使用するアセットを登録(enque)する
ブロックのスクリプトはエディタでのみ必要なものだが、スタイルはサイトの表側とエディタの両方で読み込みたいこともある。
enqueue_block_editor_assets
アクションはエディタの読み込み時にしかトリガーされない。サイトの表側でも読み込まれるようにするには、enqueue_block_assets
アクションを使うのが良い。
<?php
function gutenberg_boilerplate_es5_enqueue_common_assets() {
wp_enqueue_style(
'gutenberg-boilerplate-es5-step02',
plugins_url( 'step-02/style.css', __FILE__ ),
array( 'wp-blocks' ),
filemtime( plugin_dir_path( __FILE__ ) . 'step-02/style.css' )
);
}
add_action( 'enqueue_block_assets', 'gutenberg_boilerplate_es5_enqueue_common_assets' );
JavaScriptをサイトの表側に限定したいなら、enqueue_block_assets
アクションを使った上で、! is_admin()
の場合のみ読み込むようにすれば良い。
Introducing Attributes and Editable Fields
https://wordpress.org/gutenberg/handbook/blocks/introducing-attributes-and-editable-fields/
属性(attributes)
ブロックの出力は属性(attributes)の値によって決まる。
const { registerBlockType, Editable, source } = wp.blocks;
registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-03', {
title: 'Hello World (Step 3)',
icon: 'universal-access-alt',
category: 'layout',
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'p',
},
},
edit( { attributes, className, focus, setAttributes, setFocus } ) {
const { content } = attributes;
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
return (
<Editable
tagName="p"
className={ className }
onChange={ onChangeContent }
value={ content }
focus={ focus }
onFocus={ setFocus }
/>
);
},
save( { attributes, className } ) {
const { content } = attributes;
return <p className={ className }>{ content }</p>;
},
} );
新しいブロック型を登録する際は、attributes
プロパティによってedit
とsave
関数で受け取りたいオブジェクトの形を指定できる。それぞれの値はsource function(???)であり、ブロックをマークアップするための値を取得する。
上記サンプルコードでは、content
の値を子供のp要素から取得している。
コンポーネントとEditable
コンポーネント
ここまで、createElement
関数(またはJSX)を使ってDOMノードを作成してきた。これらの振る舞いは、「コンポーネント」に閉じ込めることもできる。このような抽象化を行うことで、処理の共通化や複雑さの隠蔽といった恩恵を得ることができる。ブロックを作成する際に利用できるコンポーネントがいくつも用意されている。サンプルコードではEditable
コンポーネントを使用している。
Editable
コンポーネントはtextarea
要素の機能強化版である。太字、イタリック体、ハイパーリンク等の機能を持っている(Editable
コンポーネントは、現行のビジュアルエディタと同様、TinyMCEを使って実装されている)。
Block Controls: Toolbars and Inspector
https://wordpress.org/gutenberg/handbook/blocks/block-controls-toolbars-and-inspector/
ブロックのカスタマイズをシンプルにして、ユーザに一貫した体験を提供するため、エディタのプレビュー機能の提供を助ける組み込みのUIパターンが用意されている。wp.blocks
グローバル変数は、エディタのインタフェースとして利用できる、いくつかの共通コンポーネントを含んでいる。
ツールバー
ユーザがブロックを選ぶと、その上にツールバーが現れ、その上にいくつものボタンが表示される。これらのブロック用コントロールは、選択された要素がEditable
コンポーネントである場合などに自動的に表示される。
ツールバーをカスタマイズして、特定のブロック専用のコントロールを読み込むこともできる。ブロック型のedit
関数の戻り値がBlockControls
要素を含んでいれば、これらのコントロールがブロックのツールバーに表示される。
const {
registerBlockType,
Editable,
BlockControls,
AlignmentToolbar,
source
} = wp.blocks;
registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-04', {
title: 'Hello World (Step 4)',
icon: 'universal-access-alt',
category: 'layout',
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'p',
},
},
edit( { attributes, className, focus, setAttributes, setFocus } ) {
const { content, alignment } = attributes;
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
function onChangeAlignment( newAlignment ) {
setAttributes( { alignment: newAlignment } );
}
return [
!! focus && (
<BlockControls key="controls">
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
</BlockControls>
),
<Editable
key="editable"
tagName="p"
className={ className }
style={ { textAlign: alignment } }
onChange={ onChangeContent }
value={ content }
focus={ focus }
onFocus={ setFocus }
/>
];
},
save( { attributes, className } ) {
const { content } = attributes;
return <p className={ className }>{ content }</p>;
},
} );
ブロックが選択されている場合のみBlockControls
を読み込むよう注意が必要である。↑ではfocus
変数の値を見ることで、BlockControls
の条件レンダリングを実現している。
Inspector
フォームのフィールドのためにより広い編集エリアがほしい場合、inspectorを使うことができる。InspectorControls
を読み込んで、edit
関数で表示すればよい。