Wordpress ブロックエディタ用プラグインを作る③ 〜実装開始〜
実際にブロックエディタープラグインを作成します。
前回でやったこと
-
@wordpress/create-block
で雛形を作成 - ブロックのnamespace、説明文、カテゴリ、アイコンを変更
現在のディレクトリ構成
wp-develop/
+- study/ # 今から実装するブロック
+- vendor/ # 既存のプラグイン・テーマを置く
+- .wp-env.json # 設定ファイル
この章のゴール
タイトル付きの枠が挿入できるブロックを目標とします。
この章の最後に最終的なスクリプトを掲載しています。
編集画面を作る
ファイル保存時に自動コンパイルするように npm run start
します。
$ cd wp-develop/study
$ npm run start
初期状態
下記は編集画面のスクリプト edit.js
の雛形による初期状態です。
こちらを編集していきます。
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.scss';
export default function Edit() {
return (
<p {...useBlockProps()}>
{__('Study – hello from the editor!', 'study')}
</p>
);
}
タイトル部分、内容部分を追加
タイトル部分はユーザーによる装飾を付けたくないので、リッチテキストではなく TextControl
を使います。本文部分は太字などを使いたいので RichText
を使います。
変更前
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.scss';
変更後
import { useBlockProps, RichText } from '@wordpress/block-editor';
import { TextControl } from '@wordpress/components';
import './editor.scss';
タイトル付き枠はセクション扱いにしたいので <p>
から <section>
に変更します。
不要なサンプルメッセージを削除して <TextControl />
、 <RichText />
を追加しました。
変更前
<p {...useBlockProps()}>
{__('Study – hello from the editor!', 'study')}
</p>
変更後
<section {...useBlockProps()}>
<TextControl />
<RichText />
</section>
コンパイルエラーが無ければ記事の編集画面に行き、 study
ブロックを挿入します。
文字のないテキストボックスと、その下には空白が入っています。
入力内容の保存先を定義する
タイトルを title
、内容を content
として保存できるように block.json
の最後に attributes
を追加します。
〜略〜
"style": "file:./build/style-index.css",
"attributes": {
"title": {
"type": "string",
"source": "text",
"selector": ".title",
"default": ""
},
"content": {
"type": "array",
"source": "children",
"selector": ".content",
"default": ""
}
}
}
title
は TextControl
を使うので文字列型の string
になっています。
content
は RichText
の中身を配列で受け取るようにしています。
selector
はそれぞれのクラス名です。
実は TextControl
の指定は下記のような簡単なものでも問題ないそうですが、一応定義できるところは定義するようにしています。
"title": {
"type": "string",
},
入力内容を保存できるようにする
edit.js
を編集して先ほど追加した TextControl
、RichText
に追記します。
export default function Edit({attributes, setAttributes}) {
return (
<section {...useBlockProps()}>
<TextControl
className="title"
type="text"
value={attributes.title}
onChange={(val)=> setAttributes({title:val})}
/>
<RichText
className="content"
tagName="p"
onChange={(val)=> setAttributes({content:val})}
value={attributes.content}
/>
</section>
);
}
どちらも onChange
で変更を受け取り setAttributes()
で内容を保存しています。
htmlの class
属性はJavaScriptの class
とぶつかってしまうので、JSXでは className
と表記します。他にもJSX独自の表記ルールなどありますので、下記のページがわかりやすくまとまってます。
props について
export default function Edit({attributes, setAttributes}) {
この部分は
export default function Edit(props) {
と書いて props.attributes
、props.setAttributes
のように利用することもできます。
他にも className
や name
など様々なパラメーター、メソッドが含まれています。
公開画面を作る
ここからは一般ユーザーに公開される画面用スクリプト save.js
を編集します。
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save({attributes}) {
return (
<section {...useBlockProps.save()}>
<span className="title">
{attributes.title}
</span>
<RichText.Content
className="content"
tagName="p"
value={attributes.content}
/>
</section>
);
}
試しにテキストを入力して、プレビューしてみました。
ちゃんとテキストが出力されています。
記事編集画面
公開画面
解説
export default function save({attributes}) {
edit.js
と同じくReactの props
を分割代入しています。
<section {...useBlockProps.save()}>
useBlockProps.save()
メソッドを使ってブロック全体のクラス名などを出力します。
<RichText.Content
className="content"
tagName="p"
value={attributes.content}
/>
RichText.Content
を使って本文部分を出力しています。
実は下記のように RichText.Content
を使わなくても表示されます。
<p>{attributes.content}</p>
ただし公式サイトによると
<strong> や <em> などのテキストフォーマットの HTML タグがエスケープされてサイトのフロントエンド側に表示される場合は恐らく save 関数の問題です。save 関数のコードが <RichText.Content tagName="h2" value={ heading } /> (JSX の場合) のようになっていることを確認してください。単純な出力 <h2>{ heading }</h2> は誤りです。
とあるので、やはり RichText.Content
を使ったほうが良さそうです。
TextControl
から RichText
に変更する
タイトルを TextControl
だと編集画面と公開画面が違いすぎるので、やはり RichText
を使うことにしました。
編集画面を修正
edit.js
を編集します。
RichText
を使うと改行が可能ですが、タイトルでは改行をさせたくないので削除する関数を追加します。
import './editor.scss';
// 改行を削除する関数
const removeBr = val => {
return val.split('<br>').join('');
}
export default function Edit({attributes, setAttributes}) {
TextControl
から RichText
に変更します。
変更前
<TextControl
className="title"
type="text"
value={attributes.title}
onChange={(val)=> setAttributes({title:val})}
/>
変更後
<RichText
className="title"
tagName="span"
allowedFormats={[]}
placeholder="タイトルを入力"
onChange={(val)=> setAttributes({title:removeBr(val)})}
value={attributes.title}
/>
allowedFormats={[]}
は文字装飾とリンクの無効化、placeholder="タイトルを入力"
はプレースホルダーを指定しています。
onChange={(val)=> setAttributes({title:removeBr(val)})}
先ほど作った関数 removeBr()
で <br>
を削除し、setAttributes()
で保存します。
公開画面を修正
save.js
を編集します。
content
と同じように RichText.Content
を使って表示します。
変更前
<span className="title">
{attributes.title}
</span>
変更後
<RichText.Content
className="title"
tagName="span"
value={attributes.title}
/>
CSSで見た目を整える
CSS的に特別なことは何もやっていないので、CSSがわかる人は読み飛ばして大丈夫です。
編集画面、公開画面の両方に反映したいので style.scss
を編集します。
後々デザイン変更することを考慮してCSS変数を使っています。
.wp-block-my-plugin-study {
--study--pading: 2rem;
--study--border-color: #000;
--study--border-width: 1px;
--study--border-style: solid;
--study--border-radius: 0;
--study--stage-color: var(--global--color-background);
--study--title-color: #000;
--study--title-size: calc(var(--global--font-size-base) * .8);
--study--title-left: calc(var(--study--pading) - (var(--study--title-size) * .5));
--study--title-top: -.5em;
--study--title-padding: 0 .5em;
position: relative;
padding: var(--study--pading);
border-style: var(--study--border-style);
border-width: var(--study--border-width);
border-color: var(--study--border-color);
border-radius: var(--study--border-radius);
.title{
position: absolute;
left: var(--study--title-left);
top: var(--study--title-top);
padding: var(--study--title-padding);
background-color: var(--study--stage-color);
color: var(--study--title-color);
line-height: 1;
font-size: var(--study--title-size);
}
}
公開用にビルド
最後に公開用にcss、jsのミニファイと難読化を行います。
$ npm run build
これでひとまず完成です。
次章ではバリエーションを作っていきます。
全スクリプト
ここまでに編集したものを掲載します。
block.json
{
"$schema": "https://json.schemastore.org/block.json",
"apiVersion": 2,
"name": "my-plugin/study",
"version": "0.1.8",
"title": "Study",
"category": "text",
"icon": "smiley",
"description": "説明文",
"supports": {
"html": false
},
"textdomain": "heart",
"editorScript": "file:./build/index.js",
"editorStyle": "file:./build/index.css",
"style": "file:./build/style-index.css",
"attributes": {
"title": {
"type": "string",
"source": "text",
"selector": ".title",
"default": ""
},
"content": {
"type": "array",
"source": "children",
"selector": ".content",
"default": ""
}
}
}
edit.js
import { useBlockProps, RichText } from '@wordpress/block-editor';
import './editor.scss';
const removeBr = val => {
return val.split('<br>').join('');
}
export default function Edit({attributes, setAttributes}) {
return (
<section {...useBlockProps()}>
<RichText
className="title"
tagName="span"
allowedFormats={[]}
placeholder="タイトルを入力"
onChange={(val)=> setAttributes({title:removeBr(val)})}
value={attributes.title}
/>
<RichText
className="content"
tagName="p"
placeholder="本文を入力"
onChange={(val)=> setAttributes({content:val})}
value={attributes.content}
/>
</section>
);
}
save.js
import { __ } from '@wordpress/i18n';
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save({attributes}) {
return (
<section {...useBlockProps.save()}>
<RichText.Content
className="title"
tagName="span"
value={attributes.title}
/>
<RichText.Content
className="content"
tagName="p"
value={attributes.content}
/>
</section>
);
}
style.scss
前の項目と同じなので省略します。
editor.scss
編集画面独自のスタイルは無いので空っぽです。
.wp-block-my-plugin-study {
}
Discussion