WordPressのGutenbergハンドブックに載っている記述そのままでは作る方法が分からず、別の方法での実装を試した内容です。
注意点
- Gutenbergがコアに入る前の段階の記事です
- 書き方だけではなく、語句や名称にも問題がある可能性があります
- バッドノウハウな状態だと思いますので、読む方は参考程度に考えてください
- 私自身の書き方がまだ固まっていないため、当ブログ内のサンプルコードにはconstやfunction、アロー関数の使用の有無など、表記揺れがあります
実現したいこと
- Gutenbergでブロック編集時にサイドバーを付ける
- サイドバー内にラジオボタンを付けて動作させる
ハンドブックでは以下のページに説明があります。
サンプル1 withState不使用
[2018.9.27 追記]
この記事を書いた当初より理解が進み、withStateを使わない方法で作っても良さそうだと思えたので、withStateを無視して作成したサンプルです。
役に立つとは思いませんが、以前のwithState使って無理矢理作ったサンプルも一応サンプル2として後述していますので見られる方は下にスクロールしてください。
//初期設定
add_action( 'enqueue_block_editor_assets', function() {
wp_enqueue_script(
'myplugin-gutenberge',
plugins_url( 'block.js', __FILE__ ),
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-editor' ]
);
} );
const { registerBlockType } = wp.blocks;
const { Fragment } = wp.element;
const {
RichText,
BlockControls,
AlignmentToolbar,
InspectorControls,
} = wp.editor;
const {
PanelBody,
RadioControl,
} = wp.components;
registerBlockType( 'my-plugin/test-inspector-radio-nostate', {
title: 'test-inspector-radio-nostate',
icon: 'universal-access-alt',
category: 'layout',
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'p',
},
alignment: {
type: 'string',
},
option: {
type: 'string',
default: 'a',
}
},
edit( { attributes, setAttributes } ) {
const { content, option, alignment } = attributes;
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
function onChangeAlignment( newAlignment ) {
setAttributes( { alignment: newAlignment } );
}
function onChangeOption( newOption ) {
setAttributes( { option: newOption } );
}
return(
<Fragment>
<BlockControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
</BlockControls>
<InspectorControls>
<PanelBody title="著者表記">
<RadioControl
label="User type"
help="The type of the current user"
selected={ option }
options={ [
{ label: 'Author', value: 'a' },
{ label: 'Editor', value: 'e' },
] }
onChange={ onChangeOption }
/>
</PanelBody>
</InspectorControls>
<RichText
key="editable"
tagName="p"
style={ { textAlign: alignment } }
onChange={ onChangeContent }
value={ content }
/>
</Fragment>
);
},
save( { attributes, className } ) {
const { content, option, alignment } = attributes;
let value = attributes.option;
const addName = ( value ) => {
switch( value ) {
case 'a':
return "Author";
break;
case 'e':
return "Editor";
break;
default:
return "John Does";
break;
}
};
return (
<div>
<RichText.Content
style={ { textAlign: alignment } }
value={ content }
tagName="p"
/>
<p class="author">By {addName(value)} </p>
</div>
);
},
} );
サンプル2 withState使用
以下は「ラジオボタンで著者名表示を変える」という動作を目的としたサンプルですが、ハンドブックにあるwithStateをなんとか使おうとして半ば無理矢理作ったものです。
//初期設定
add_action( 'enqueue_block_editor_assets', function() {
wp_enqueue_script(
'myplugin-gutenberge',
plugins_url( 'block.js', __FILE__ ),
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-editor', 'wp-compose' ]
);
} );
const { registerBlockType } = wp.blocks;
const { Fragment } = wp.element;
const {
RichText,
BlockControls,
AlignmentToolbar,
InspectorControls,
} = wp.editor;
const {
PanelBody,
RadioControl,
} = wp.components;
const { withState } = wp.compose;
const edit = ( {attributes, className, setAttributes, option, setState} ) => {
const { content, alignment, newOption } = attributes;
option = newOption;
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
function onChangeAlignment( newAlignment ) {
setAttributes( { alignment: newAlignment } );
}
function onChangeOption( newOption ) {
setAttributes( { newOption: newOption } );
}
return (
<Fragment>
<BlockControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
</BlockControls>
<InspectorControls>
<PanelBody title="著者表記">
<RadioControl
label="User type"
help="The type of the current user"
selected={ option }
options={ [
{ label: 'Author', value: 'a' },
{ label: 'Editor', value: 'e' },
] }
onChange={ ( option ) => { setState( { option }, onChangeOption(option)) } }
/>
</PanelBody>
</InspectorControls>
<RichText
key="editable"
tagName="p"
style={ { textAlign: alignment } }
onChange={ onChangeContent }
value={ content }
/>
</Fragment>
);
}
const save = ( { attributes, className} ) => {
const { content, alignment, newOption } = attributes;
let value = attributes.newOption;
function addName( value ) {
switch( value ) {
case "a":
return "Author";
break;
case "e":
return "Editor";
break;
default:
return "John Does";
break;
}
}
return (
<div >
<RichText.Content
style={ { textAlign: alignment } }
value={ content }
tagName="p"
/>
<p class="author2">By { addName(value) } </p>
</div>
);
}
registerBlockType( 'my-plugin/test-inspector-radio', {
title: 'test-inspector-radio',
icon: 'universal-access-alt',
category: 'layout',
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'p',
},
alignment: {
type: 'string',
},
newOption: {
type: 'string',
default: 'a',
}
},
edit: withState() (edit),
save: save,
} );
ハンドブックではRadioControlの使用に際しwithStateを使っていますが、この形で値を取り出す公式的な方法がわからず、主に下記ページを参考にしながらかなり無理矢理に作った状態です。
withStateで設定できる初期値を使わず、attributesで初期値の設定を行っています。
説明入りサンプル
以下は上記と同じコードにコメントで説明を入れたものです。
//ブロックが作れるようにregisterBlockTypeを読み込む
const { registerBlockType } = wp.blocks;
//editやsave内で<Fragment>が使えるように、 wp.elementから読み込む
const { Fragment } = wp.element;
//editやsave内で<RichText>などが使えるように、 wp.editorから読み込む
//サイドバー内への配置をしている<InspectorControls>もここで設定
const {
RichText,
BlockControls,
AlignmentToolbar,
InspectorControls,
} = wp.editor;
//editやsave内で<RadioControl>などが使えるように、 wp.componentsから読み込む
const {
PanelBody,
RadioControl,
} = wp.components;
//withStateが使えるように、 wp.composeから読み込む
const { withState } = wp.compose;
//編集画面用の設定を作成
//withStateを使う際に分かりやすくするために、registerBlockTypeから分離
//optionとsetStateはサンプル通りで、他は必要に応じて追加
const edit = ( {attributes, className, setAttributes, option, setState} ) => {
//attributesでまとめていた各属性を分けて使えるようにする
//こうしておけば{alignment}と書けばalignment: centerのように出力される
const { content, alignment, newOption } = attributes;
//stateとは別にattributes内にnewOptionを作っており(この点後述)、そのnewOptionの値をstate内のoptionの値に入れて、保存後のラジオボタンの選択を反映させている
option = newOption;
//RichTextへの入力内容を取得して更新する
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
//AlignmentToolbarの値を取得して更新する
function onChangeAlignment( newAlignment ) {
setAttributes( { alignment: newAlignment } );
}
//選択されたラジオボタンのvalueをattributes内のnewOptionに設定
function onChangeOption( newOption ) {
setAttributes( { newOption: newOption } );
}
return (
<Fragment>
{//ブロックの上の場所を指定
}
<BlockControls>
{//並び方向を設定するUIをこれだけで出力できる
}
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
</BlockControls>
{//サイドバーの場所を指定
}
<InspectorControls>
{/*
個別に分けるために設定
titleを設定するとトグルで開閉式にできる。必須ではない。
*/}
<PanelBody title="著者表記">
{//ラジオボタンの設定
}
<RadioControl
label="User type"
help="The type of the current user"
selected={ option }
options={ [
{ label: 'Author', value: 'a' },
{ label: 'Editor', value: 'e' },
] }
{/*
ラジオボタンの設定
setStateのコールバックでonChangeOptionを動作させてnewOptionsにも同時に同じ値を送る
*/}
onChange={ ( option ) => { setState( { option }, onChangeOption(option)) } }
/>
</PanelBody>
</InspectorControls>
{//リッチテキストエディタの設定
}
<RichText
key="editable"
tagName="p"
style={ { textAlign: alignment } }
onChange={ onChangeContent }
value={ content }
/>
</Fragment>
);
}
//editと形をあわせる意味でregisterBlockTypeから分離
const save = ( { attributes, className} ) => {
//最初に設定し、edit内で操作したattributesの値をattributesと書くことでまとめて引数にしている
const { content, alignment, newOption } = attributes;
//分岐に使うためにnewOptionの値を取り出す
let value = attributes.newOption;
//分岐に使うためにnewOptionの値を頼りに、出力内容を変更する
//defaultはまず要らないはずだが一応設定
function addName( value ) {
switch( value ) {
case "a":
return "Author";
break;
case "e":
return "Editor";
break;
default:
return "John Does";
break;
}
}
return (
<div >
<RichText.Content
style={ { textAlign: alignment } }
value={ content }
tagName="p"
/>
{//上で設定した関数を使って値を出力
}
<p class="author2">By { addName(value) } </p>
</div>
);
}
//編集画面用の設定を作成
registerBlockType( 'my-plugin/test-inspector-radio', {
//iconやcategoryなどの設定(今回は適当に決定)
title: 'test-inspector-radio',
icon: 'universal-access-alt',
category: 'layout',
//属性とその値を利用できるように設定。初期設定のようなもの。
//atributesに入れてしまえば、edit内の値をsave内に簡単に持ち込める
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'p',
},
alignment: {
type: 'string',
},
newOption: {
type: 'string',
//ラジオボタンの初期値を設定
default: 'a',
}
},
//editは投稿画面内の内容を設定
//edit全体を囲うようにwithStateを記述
//ハンドブックにある初期値は使わない
edit: withState() (edit),
//saveは保存時の内容を設定。基本的にはそのまま出力されるので、記事表示時の内容とほぼ同義。
//今回は分離しているのでこれだけ
save: save,
} );
witStateの使い方を把握できなかったのが根本的な原因といえますが、withState内で変更された値(今回はラジオボタンのvalue)の保存と保存後の取り出し方法に関して無理矢理な方法をとっています。
具体的にはsetStateのコールバック関数を使って、stateと同じ値をattrigutesに設定した属性に設定し、それを保存時や保存後の取り出し時に利用しています。
結果としてなんとか動くところまでは来ましたが、明らかに公式が想定していない作りになりました。
そのため、今後目にする記事や情報次第で追記などではなく当記事を削除する可能性もありますので、その点ご容赦ください。
関連記事
Gutenberg(ブロックエディタ)に関連する記事一覧。
- [Gutenberg対応版]WordPressで複数のCSSをまとめてインラインCSSとして出力する
- @wordpress/create-blockで一つのプラグインに複数のブロックを入れる
- @wordpress/wp-env と @wordpress/create-block で簡単にブロック開発環境を作る
- 3度目のブロック開発環境(Docker Desktopとcreate-block)
- Gutenberg(ブロックエディタ)メモ
- Gutenberg(ブロックエディタ)メモ -Gutenbergの使い方で迷うところ
- Gutenberg(ブロックエディタ)メモ -ハンドブックでわからないところ1
- Gutenberg(ブロックエディタ)メモ -ハンドブックでわからないところ2
- Buttonを使う(MediaUploadとRichTextも含む)
- metaデータを設定する
- Templatesとplaceholderを使う
- Toggleを使う
- カスタムHTMLを使う
- サイドバー(Inspector)を設定する
- サイドバーを作ってcheckboxを使う
- サイドバーを作ってラジオボタンを使う [現在表示中]
- ショートコードの代替案的なブロックを作る
- ラジオボタンでクラスを変更可能なコードエディタブロックを作る
- 登録されているショートコードの一覧を表示したブロックを作る
- AddQuicktagのGutenberg対応に関して
- Classic Editorプラグインに関して
- wp_is_mobile関数を利用して出し分け機能をもったブロックを作る
- 任意のHTMLタグを範囲選択で挿入可能なツールバーを付ける
- 任意のHTMLタグを範囲選択で挿入可能なボタンをRichTextのツールバーに追加する
- 自動でテーマCSSの指定箇所をGutenberg用CSSとして用いる方法の検討
- 自動で出力されるブロック用のCSSを取除く
- Gutenberg関連の参考サイト:メモ
- WPのsetMeta()で複数のキーと値を保存する
- WPのブロックエディタでTypeError: Cannot read property ‘firstChild’ of nullのエラー:メモ
- WPのブロックエディタでUncaught Error: Minified React error #321のエラー:メモ
- WPのブロックエディタでタグをドロップダウンで変更する:メモ
- WPのブロックエディタでブロック追加用ボタンを表示させる:メモ
- WPのブロックエディタで親の値を子に設定する:メモ
- WPのブロック作成メモ
- WPの独自ブロックが設定されている時のみCSSやJSをフロントに表示する方法
- ブロック作成時のclassNameに関するメモ
- ブロック開発の環境構築におけるwp-scriptsとCreate Guten Blockのメモ
1人がこの記事を評価
役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。
連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。