Wordpress Gutenberg よく使いそうなコンポーネントまとめ

#この記事は？

Wordpressの新エディタGutenbergをいじってて
よく使いそうだと思ったコンポーネントをまとめていきます
追記編集していきます

TextControl と TextareaControl
=
テキスト編集のコンポーネント。
onChangeでイベントオブジェクトじゃなく中身の文字列だけが渡されるようになってるので、値の取り出しとかしなくていいので普通にtextareaとか書いちゃうより楽です。

```jsx:JSX

const {TextControl, TextareaControl} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<TextControl
				onChange={(newText1)=>setAttributes({text1: newText1});}
			/>,
			<TextareaControl
				onChange={(newText2)=>setAttributes({text2: newText2});}
			/>
		];
	}
);
```

RichText
=
ちょっとした文字装飾ができるテキスト編集のコンポーネント。
使い方は基本TextControlと同じなのだけどこいつはwp.componentsではなくwp.editorにいます。

```jsx:JSX

const {RichText} = wp.editor;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<RichText
				onChange={(newText)=>setAttributes({text: newText});}
			/>
		];
	}
);
```

RichTextで各文字に適用できる文字スタイルは
[registerFormatType](https://wordpress.org/gutenberg/handbook/designers-developers/developers/packages/packages-rich-text/#registerFormatType)で増やすことができます

以下smallを追加してみるコード


```jsx
const {Fragment}=wp.element;
const {RichText,RichTextToolbarButton,RichTextShortcut} = wp.editor;
const {registerFormatType,toggleFormat}=wp.richText;
const {__}=wp.i18n;

registerFormatType('my/editor',{
	title:'small',
	tagName:'small',
	className:null,
	edit({isActive,value,onChange}){
		const onToggle=()=>onChange(toggleFormat(value,{type:'catpow/small'}));
		
		const icon=(
			<svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true">
				<path d="M5.6,16.7l3.6-9.4h1.3l3.8,9.4H13l-1.1-2.8H8l-1,2.8H5.6z M8.3,12.9h3.2l-1-2.6C10.2,9.5,10,8.9,9.9,8.4
		C9.7,9,9.6,9.6,9.3,10.1L8.3,12.9z"/>
			</svg>
		);

		return [
			<Fragment>
				<RichTextShortcut
					type={'primary'}
					character={'-'}
					onUse={onToggle}
				/>
				<RichTextToolbarButton
					icon={icon}
					title={'small'}
					onClick={onToggle}
					isActive={isActive}
					shortcutType={'primary'}
					shortcutCharacter={'-'}
				/>
			</Fragment>
		];
	}
});
```
iconには[dash-icon](https://developer.wordpress.org/resource/dashicons/#menu)の名前（リンク先で書かれてる名称の"dashicon-"より後ろ）で指定する他にSVGを使うこともできます

RichTextShortcutのtypeの指定はそれぞれ以下のように修飾キーに対応

<table>
 <thead><tr><td></td><td>Mac</td><td>Win</td></tr>
 <tbody>
  <tr><th> primary </th><td>[ COMMAND ] </td><td> [ CTRL ]</td><tr>
  <tr><th> primaryShift </th><td>[ SHIFT, COMMAND ]</td><td>  [ CTRL, SHIFT ]</td><tr>
  <tr><th> primaryAlt </th><td>[ ALT, COMMAND ]</td><td>[ CTRL, ALT ]</td><tr>
  <tr><th> secondary </th><td>[ SHIFT, ALT, COMMAND ]</td><td>[ CTRL, SHIFT, ALT ]</td><tr>
  <tr><th> access </th><td>[ CTRL, ALT ]</td><td>[ SHIFT, ALT ]</td><tr>
  <tr><th> ctrl </th><td>[ CTRL ]</td><td>[ CTRL ]</td><tr>
  <tr><th> alt </th><td>[ ALT ]</td><td>[ ALT ]</td><tr>
  <tr><th> ctrlShift </th><td>[ CTRL, SHIFT ]</td><td>[ CTRL, SHIFT ]</td><tr>
  <tr><th> shift </th><td>[ SHIFT ]</td><td>[ SHIFT ]</td><tr>
  <tr><th> shiftAlt </th><td>[ SHIFT, ALT ]</td><td>[ SHIFT, ALT ]</td><tr>
 </tbody>
</table>

RichTextの値はsaveでの出力の際には``<RichText.Content value={value}/>``のようにして出力しなくてはなりません。WP5.4以前はTextControlとかと同じノリで``{value}``と書いても解決してくれましたが、WP5.5以降はちゃんと書かなくてはいけなくなりました。

CheckboxControl
=
チェックボックスのコンポーネント
多分一番使ってるコンポーネント
チェックボックスをポチポチするだけで
要素を入れたり消したりできるのはユーザー的に便利

```jsx:JSX

const {RangeControl} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<CheckboxControl
				label='真偽値'
				help={bool?'真':'偽'}
				onChange={(bool)=>{setAttributes({bool:bool});}}
				checked={bool}
			/>
		];
	}
);
```


RangeControl
=
スライダーで数値の入力できるコンポーネント
ユーザー入力を特定の範囲の数値に保証できるのがいいところ
こういうこと簡単にできるのは便利

```jsx:JSX

const {RangeControl} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<RangeControl
				label='数値'
				onChange={(number)=>{setAttributes({number:number});}}
				value={number}
				min={0}
				max={12}
			/>
		];
	}
);
```

ServerSideRender
=
php側のregister_block_typeでrender_callbackを指定して
サーバーサイドでレンダリングするように作られたブロックをプレビューするコンポーネント。
使い方とかは公式ハンドブックの[Creating dynamic blocks](https://wordpress.org/gutenberg/handbook/blocks/creating-dynamic-blocks/)で大体わかります、大体だけ。
要は編集画面上で検索とかサーバーサイドの処理が絡むようなものをプレビューしながら編集できるわけです。

フォームの埋め込みなどショートコードでやってたことをもっと直感的にできるようになるわけですが、だからと言ってショートコードの出番がなくなるわけでもありません。
ショートコードにはテキストの途中の任意の場所で使用できるという利点があります。

また、ショートコードはブロックのレンダリングより後に行われるので、ブロックにショートコードを含むコードを出力させることで、ショートコードを組み合わせたり再利用したブロックというのも実現します。



```jsx:JSX

//const {ServerSideRender} = wp.components; 
const {serverSideRender:ServerSideRender}=wp;


registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<ServerSideRender
				block='myPlugin/myBlock'
				attributes={attributes}
			/>
		];
	}
);
```

注意点としてはattributesの設定をjs側ではなくphp側
つまりregister_block_typeのパラメータで指定しないと
サーバーサイドでエラーになってしまうこと

考えてみりゃ当たり前ですが、考えずにやってるとつまづきます、つまづきました。

ということでregister_block_typeでrender_callbackとattributesは大体セットで指定することになります。

こんな感じに

```php:PHP
register_block_type('myPlugin/myBlock',[
	'render_callback'=>function($attr){
		return sprintf('<p class="%s">MyBlock</p>',$attr['className']);
	},
	'attributes'=>[
		'className'=>['default'=>'myclass']
	]
]);
```

2023/04/05追記
WordPress6.2からServerSideRenderの読み込み方が変わりました。

```jsx:JSX

const {ServerSideRender} = wp.components; //6.1以前
↓
const {serverSideRender:ServerSideRender} = wp; //6.2以降

```



InspectorControls と PanelBody
=
ブロックを選択した時に表示されるサイドバーのコンポーネント。
PanelBodyでtitleを指定すると折りたたみにできます。
サイドバーはまず基本この二つを使って作ることになるだろうと思います。

```jsx:JSX

const {InspectorControls} = wp.editor;
const {PanelBody} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<InspectorControls>
				<PanelBody title="パネルのタイトル">
				//ここにパネルの中身を書く
				</PanelBody>
			</InspectorControls>
		];
	}
);
```

PanelBodyは本来はPanelに入れてPanelHeaderと共に使うものっぽいんですが
正直Panelコンポーネントは見にくい使いにくいです、PanelBodyだけでいいです。

InspectorControlsってかなり使いそうなものなのに、公式ハンドブックには[Block Controls: Toolbars and Inspector](https://wordpress.org/gutenberg/handbook/blocks/block-controls-toolbars-and-inspector/)のページで「InspectorControlsはHTMLモードでも表示されるからテキスト編集とかのは入れちゃダメだよ」という注意書きにしか登場してなくて、使い方とか全然書かれてません。

この情報が書かれていないハンドブックは不親切だと思います（切実）

BaseControl
=
サイドバーの入力項目の入れ物になるコンポーネント。
オリジナルのコンポーネントに、基本コンポーネントと同様にラベルやヘルプをつけられます。

```jsx:JSX

const {InspectorControls} = wp.editor;
const {PanelBody, BaseControl} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<InspectorControls>
				<PanelBody title="パネルのタイトル">
					<BaseControl label="入力項目名" help="ヘルプ">
						入力項目
					</BaseControl>
				</PanelBody>
			</InspectorControls>
		];
	}
);
```

InnerBlocks
=
ブロックを入れ子にするためのコンポーネントです。
このコンポーネントは特に特別なブロックで、他のブロックとは処理されるフェーズが異なり、独特な制約が伴います。

```jsx:JSX

const {InnerBlocks} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		return [
			<InnerBlocks template={[['core/paragraph'],['core/image']]}/>,
		];
	},
	save({attributes,className,setAttributes}){
		return <InnerBlocks.Content/>
	}
);
```
allowedBlocksで入れ子にできるブロックを制限しつつ自由に組み合わせ
templateで指定した固定の構造で組み合わせ

値やID与えるようになっていないため
一つのブロックにInnerBlocksは一つしか置けないです

また、saveはinnerBlocksを含む場合***戻り値を配列にすることができません***
saveは単一のコンポーネントを返す必要があります

この情報が書かれていないハンドブックは不親切だと思います（切実）

詳しい情報は[GitHub](https://github.com/WordPress/gutenberg/tree/e5d77bd5e7dea2147a503cdad1e89945648753e1/packages/editor/src/components/inner-blocks)で

また、innerBlocksを含むブロック、例えばcore/columnsなどは
[registerBlockStyleするとクラッシュするという問題](https://github.com/WordPress/gutenberg/issues/9897)があります
これはサイドバーでスタイル適用のプレビューをするタイミングでは
必要なデータがinnerBlocksの場合は揃っていないのが原因
なので上記の回答の中にもあるように、innerBlocksを含むブロックタイプの場合は
中身が空のコンポーネントを返すようにしてクラッシュを回避するなどします

そのうち修正されるとは思いますが5.1.1ではまだ修正されてません

```jsx
// core/columnsでregisterBlockStyleがエラーを起こすバグの回避
wp.hooks.addFilter(
	'editor.BlockEdit',
	'my/editor',
	wp.compose.createHigherOrderComponent(function(BlockEdit){
		return function(props){
			var content=wp.element.createElement(BlockEdit,props);

			if(props.name==='core/columns' && typeof props.insertBlocksAfter==='undefined'){
				return <Fragment><div></div></Fragment>
			}

			return <Fragment>{content}</Fragment>;
		};
	},'allowColumnStyle')
);
```

Fragment
=

Reactでお馴染みの何も出力しないコンポーネント。
複数のコンポーネントをまとめて一つのコンポーネントとして扱いたいとかに使います。

また、Gutenbergはsaveの返すコンポーネントの``className``に
``wp-block-ブロック名``のクラスを自動的に補完する様になっているのですが
ブロックのクラスをattributesの方でコントロールしたい場合にこれが邪魔になります。

saveで返すコンポーネントを``<Fragment>``でラップすることで
このクラス補完の処理を回避することができます。


```jsx
registerBlockType('myPlugin/myBlock',{
	save({attributes}){
		return (
			<Fragment>
				<MyComponent className={attributes.classes}/>
			</Fragment>
		);
	}
);
```

[Block API version 2](https://make.wordpress.org/core/2020/11/18/block-api-version-2/)から``wp-block-ブロック名``のクラスなど
Gutenbergが自動で付与していたプロパティは
``useBlockProps``を使って明示的に付与しなければ付与されることはなくなりました


BlockControls と Toolbar
=
ブロックを選択した時に左上に出てくるツールバーを拡張するために使うコンポーネント。

```jsx
const {BlockControls} = wp.blockEditor;
const {Toolbar} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		const {EditMode=false}=attributes;
		return (
			<BlockControls>
				<Toolbar
					controls={[
						{
							icon:'edit',
							title:'編集モード',
							isActive:EditMode,
							onClick:() => setAttributes({EditMode:!EditMode})
						}
					]}
				/>
			</BlockControls>
		);
	}
);
```


BlockAlignmentToolbar
=
BlockControlsに入れて使うブロックのレイアウトを選択するツールバーです。
値はleft,center,rightで固定です。

```jsx
const {BlockControls} = wp.blockEditor;
const {Toolbar} = wp.components;

registerBlockType('myPlugin/myBlock',{
	edit({attributes,className,setAttributes}){
		const {blockAlignment='left'}=attributes;
		return (
			<BlockControls>
				<BlockAlignmentToolbar
					value={blockAlignment}
					controls={['left','center','right']}
					onChange={(blockAlignment)=>{setAttributes({blockAlignment})} }
				/>
			</BlockControls>
		);
	}
);
```

PluginSidebar と PluginSidebarMoreMenuItem
=
記事編集時に右側に出てくるサイドバーを拡張するためのコンポーネント。
``wp.blocks.registerBlockType``ではなく``wp.plugins.registerPlugin``で使います。

``PluginSidebar``が本体、``PluginSidebarMoreMenuItem``でサイドバーの表示項目の設定に追加しないと表示する術がなくなってしまうので、``PluginSidebar``と``PluginSidebarMoreMenuItem``はいつもセットで使うことになるかと思います。


```jsx
const {registerPlugin}=wp.plugins;
const {PluginSidebarMoreMenuItem,PluginSidebar}=wp.editPost;

const MySidebarPanelComponent = (props) => {
    return [
		<PluginSidebarMoreMenuItem target="MySidebarPanel">MySidebarPanel</PluginSidebarMoreMenuItem>,
        <PluginSidebar
            name="MySidebarPanel"
            title="MySidebarPanel"
            icon={edit}
        >
			<PanelBody title="MySidebarPanel" initialOpen={false}>
				MySidebarPanel
			</PanelBody>
        </PluginSidebar>
    ];
};
registerPlugin('MySidebarPanelComponent', { render: MySidebarPanelComponent } );

```