WordPressのGutenbergハンドブックに載っている記述ではよく分かりませんでしたが、ほぼ完成のコードを見ることができ、それに少し手を入れる形で作った内容です。
注意点
- Gutenbergがコアに入る前の段階の記事です
- 書き方だけではなく、語句や名称にも問題がある可能性があります
- 私自身の書き方がまだ固まっていないため、当ブログ内のサンプルコードにはconstやfunction、アロー関数の使用の有無など、表記揺れがあります
実現したいこと
- ハンドブックにあるButtonを使う
ハンドブックでは以下のページに説明があります。
当初は用途を「何らかのボタンを記事に出力するためのコンポーネント」だと勘違いしてしまい作り方がわかりませんでしたが、いくらか試しながらサンプルは無いかと調べたところ、以下の記事を見つけてようやく役割を理解できました。
あくまで投稿欄内のブロックに使うUI用のコンポーネントであり、記事に出力するボタンを作るということではありませんでした(出力用のボタンもこのコンポーネントを使うのかもしれませんが)。
なお、以下のサンプルは上記記事の質問に記載されたコードをほとんどそのまま使わせてもらっています。
サンプル
以下は「見出しとコンテンツと画像を出力するパーツ」「アップロードボタンを作って画像をアップロードする」という動作を目的としたサンプルです。
なお、本来の動作は「画像の取得に成功するとボタンは消えて画像だけが表示される」なのですが、ボタンを付けたままの方がわかりやすいのではとMediaUploadのrender内を改造して試しています。
この形はよろしくないように思いますが、動作自体は期待したものになったようです。
//初期設定
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 { MediaUpload, RichTexts } = wp.editor;
const { Fragment } = wp.element;
const { Button } = wp.components;
const testImgSetHeadingStyle = { borderLeft: '5px solid #555', paddingLeft: '.5em',fontWeight: 'bold' };
const testImgSetTextareaStyle = { border: '1px solid #ccc' };
registerBlockType( 'my-plugin/test-img-set', {
title: 'test-img-set',
icon: 'universal-access-alt',
category: 'layout',
attributes: {
title: {
type: 'array',
source: 'children',
selector: 'h2',
},
content: {
type: 'array',
source: 'children',
selector: 'p',
},
mediaID: {
type: 'number',
},
mediaURL: {
type: 'string',
source: 'attribute',
selector: 'div',
attribute: 'data-src',
}
},
edit( { attributes, className, setAttributes } ) {
const { mediaID, mediaURL, title, content } = attributes;
const onChangeTitle = value => {
setAttributes( { title: value } );
};
const onSelectImage = media => {
setAttributes( {
mediaURL: media.url,
mediaID: media.id,
} );
};
const onChangeContent = newContent => {
setAttributes( { content: newContent } );
};
return (
<div className={ className }>
<p style={testImgSetHeadingStyle}>Title</p>
<RichText
tagName="h2"
placeholder={ 'Page Header' }
value={ title }
onChange={ onChangeTitle }
style={testImgSetTextareaStyle}
/>
<hr />
<p style={testImgSetHeadingStyle}>Content</p>
<RichText
tagName="p"
placeholder={ 'Page Content' }
value={ content }
onChange={ onChangeContent }
style={testImgSetTextareaStyle}
/>
<hr />
<MediaUpload
onSelect={ onSelectImage }
type="image"
value={ mediaID }
render={ ( { open } ) => (
<Fragment>
<div>
{ mediaID
? <Button className={ 'image-button' } onClick={ open }>
<img src={ mediaURL } />
</Button>
: <p>No Image</p>
}
</div>
<Button className={ 'button button-large' } onClick={ open }>
Upload Image
</Button>
</Fragment>
)}
/>
</div>
);
},
save( { attributes, className } ) {
const { mediaID, mediaURL, title, content } = attributes;
const divStyle = {};
if( mediaURL ) {
divStyle.backgroundImage = 'URL('+mediaURL+')';
}
return (
<div className={ className } data-src={ mediaURL } style={ divStyle }>
<h2>{ title }</h2>
<p>{ content }</p>
</div>
);
},
});
説明入りサンプル
以下は上記と同じコードにコメントで説明を入れたものです。
//ブロックが作れるようにregisterBlockTypeを読み込む
const { registerBlockType } = wp.blocks;
//editやsave内で<RichText>などが使えるように、 wp.editorから読み込む
const { MediaUpload, RichText } = wp.editor;
//editやsave内で<Fragment>が使えるように、 wp.elementから読み込む
const { Fragment } = wp.element;
//editやsave内で<Button>が使えるように、 wp.componentから読み込む
const { Button } = wp.components;
//装飾用CSSを設定
const testImgSetHeadingStyle = { borderLeft: '5px solid #555', paddingLeft: '.5em',fontWeight: 'bold' };
const testImgSetTextareaStyle = { border: '1px solid #ccc' };
//編集画面用の設定を作成
registerBlockType( 'my-plugin/test-img-set', {
//iconやcategoryなどの設定(Title以外は参考にしたコードのまま決定)
title: 'test-img-set',
icon: 'universal-access-alt',
category: 'layout',
//属性とその値を利用できるように設定。初期設定のようなもの。
attributes: {
title: {
type: 'array',
source: 'children',
selector: 'h2',
},
content: {
type: 'array',
source: 'children',
selector: 'p',
},
mediaID: {
type: 'number',
},
//save関数内を見るとこの設定の具体的な理由がわかる。
mediaURL: {
type: 'string',
source: 'attribute',
selector: 'div',
attribute: 'data-src',
}
},
//editは投稿画面内の内容を設定
edit( { attributes, className, setAttributes } ) {
//attributesでまとめていた各属性を分けて使えるようにする
//こうしておけば{mediaID}と書けばmediaID: num(数値)のように出力される
const { mediaID, mediaURL, title, content } = attributes;
//タイトル用のRichText内の文字列が変化したら、attributesのtitleに都度値をセットする
const onChangeTitle = value => {
setAttributes( { title: value } );
};
//コンテンツ用のRichText内の文字列が変化したら、attributesのtitleに都度値をセットする
const onChangeContent = newContent => {
setAttributes( { content: newContent } );
};
//MediaUploadで画像を選ぶとonSelectによってここが呼ばれ、urlとidがそれぞれatribbutesのmediaURLとmediaIDに設定される
const onSelectImage = media => {
setAttributes( {
mediaURL: media.url,
mediaID: media.id,
} );
};
return (
<div className={ className }>
<p style={testImgSetHeadingStyle}>Title</p>
<RichText
tagName="h2"
placeholder={ 'Page Header' }
value={ title }
onChange={ onChangeTitle }
style={testImgSetTextareaStyle}
/>
{//今回は試しでhrも使用
}
<hr />
<p style={testImgSetHeadingStyle}>Content</p>
<RichText
tagName="p"
placeholder={ 'Page Content' }
value={ content }
onChange={ onChangeContent }
style={testImgSetTextareaStyle}
/>
<hr />
<MediaUpload
{//画像が選択されたらonSelectImageを呼ぶ
}
onSelect={ onSelectImage }
type="image"
value={ mediaID }
//MediaUploadの出力内容を設定
render={ ( { open } ) => (
<Fragment>
<div>
{ mediaID
{//mediaIDが取れればimage-buttonクラスを付けて、画像アップローダーを表示させ、クリックで選択画面を出す
}
? <Button className={ 'image-button' } onClick={ open }>
<img src={ mediaURL } />
</Button>
{//mediaIDが取れなければ、No Imageと表示(=初期状態)
}
: <p>No Image</p>
}
</div>
{//onClickでopneが呼ばれて画像の値を取得
}
<Button className={ 'button button-large' } onClick={ open }>
Upload Image
</Button>
</Fragment>
)}
/>
</div>
);
},
//saveは保存時の内容を設定。基本的にはそのまま出力されるので、記事表示時の内容とほぼ同義。
//最初に設定し、edit内で操作したattributesの値をattributesと書くことでまとめて引数にしている
save( { attributes, className } ) {
//attributesでまとめていた各属性を分けて使えるようにする
const { mediaID, mediaURL, title, content } = attributes;
//divStyleという定数を新たに定義
const divStyle = {};
//mediaURLがあればdivStyleにbackgroundImageという名称でプロパティを設定して値をいれる
//この状態で{divStyle}と書くとbackgroundImage:'URL(画像のURL)'という形で出力されるので、そのままスタイル属性の値に使える(JSではbackground-imageではなく、backgroundImageのため)
if( mediaURL ) {
divStyle.backgroundImage = 'URL('+mediaURL+')';
}
return (
{/*
//背景画像にdivStyle.backgroundImageの値を出力
//このサンプルだけではdata-srcは利用されていないが、参考になるのでサンプル通り記載\
//data-srcは使っていませんが、こういう形もあるという小さな例として一応参考にしたコードのまま記載しています
*/}
<div className={ className } data-src={ mediaURL } style={ divStyle }>
{//RichText使用時の入力内容出力には、RichText.Contentを使った方が安全かもしれません
}
<h2>{ title }</h2>
{//RichText使用時の入力内容出力には、RichText.Contentを使った方が安全かもしれません
}
<p>{ content }</p>
</div>
);
},
});
補足
MediaUploadの動作はまだ確認できていなので、説明は推測が大半です。
いずれにせよ、コードの全体が示されていればそういう推測も容易になりますし、付随して複数の部分の記述や動作を確認できるので、今回の参考ページには非常に感謝しています。
関連記事
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のメモ
2人がこの記事を評価
役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。
連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。