【WordPressブロック開発】RichTextコンポーネント

WordPressのエディターにテキスト入力UIを表示するコンポーネントには、TextControlコンポーネントとRichTextコンポーネントがあります。より柔軟なブロックの開発が行えるRichTextコンポーネントを見ていきます。

TextControlコンポーネントとRichTextコンポーネント

Text Controlを使用するデメリット

  • フロントエンドとエディターのセレクタが異なる
    • フロントエンド:<p>
    • エディター:<input>
  • ブロックツールバーの装飾が使用不可

RichTextを使用するメリット

  • 編集画面、表示画面での一貫したスタイリング
    • エディターとフロントエンドのマークアップが一致する。
    • 任意のタグが使用可能
  • 他とマッチするプレースホルダーテキスト
  • フォーマットオプションの制御
    • インライン装飾機能が使用可

RichTextコンポーネントを使用する

edit.jsを編集

import { TextControl } from "@wordpress/components";
// RichTextコンポーネントをインポート
import { RichText, useBlockProps } from "@wordpress/block-editor";

export default function Edit({ attributes, setAttributes }) {
	const { message } = attributes;
	const blockProps = useBlockProps();

	return (
		<div {...blockProps}>
			{/* RichText に変更 */}
			<RichText
				value={message}
				onChange={(value) => {
					setAttributes({ message: value });
				}}
			/>
		</div>
	);
}

save.jsを編集します。

import { useBlockProps } from "@wordpress/block-editor";

export default function save({ attributes }) {
	const { message } = attributes;

	return <div {...useBlockProps.save()}>{message}</div>;
}

エディター側のマークアップを一部省略して示します。階層構造は、div > div となっています。

<div
	class="block-editor-block-list__block wp-block is-selected wp-block-create-block-my-block"
	data-type="create-block/my-block"
>
	<div
		class="block-editor-rich-text__editable rich-text"
	>
		&#xFEFF;
	</div>
</div>

フロントエンドのマークアップを示します。階層構造は、divのみです。

<div class="wp-block-create-block-my-block">
    test test test test test test 
</div>

エディター側のタグを変更

マークアップはコンテンツが段落タグで囲われるように指定していきます。

  • エディター: div > div > p
  • フロントエンド:p

エディター側のマークアップをフロントエンドに近づけるため、edit.jsを編集ます。

	return (
		<div {...useBlockProps()}>
			<RichText
				// フロントエンド側のタグを変更
				tagName="p"
				value={message}
				onChange={(value) => {
					setAttributes({ message: value });
				}}
			/>
		</div>
	);

フロントエンドのマークアップは、div > div > p になりました。

<div
  tabindex="0"
  class="block-editor-block-list__block wp-block is-selected wp-block-create-block-my-block"
  data-type="create-block/my-block"
>
  <p class="block-editor-rich-text__editable rich-text">
    test test test test test
  </p>
</div>

フロントエンドのタグを変更

save.jsをRichTextコンポーネントに書き換えます。

import { RichText, useBlockProps } from "@wordpress/block-editor";

export default function save({ attributes }) {
	const { message } = attributes;

	return (
		<div {...useBlockProps.save()}>
			<RichText.Content
				// フロントエンドのタグを変更
				tagName="p"
				value={message}
			/>
		</div>
	);
}

フロントエンドのマークアップに<p>が追加されました。

<div class="wp-block-create-block-my-block">
    <p>teat</p>
</div>

ルートの<div>除去

ここまででマークアップは次のようになっています。

  • エディター: div > div > p
  • フロントエンド:div > p

エディター側の<div>を除去して、フロントエンドのマークアップとの統一を完成させます。

	return (
		<RichText
			// RichText内に{...useBlockProps()}を渡す
			{...useBlockProps()}
			tagName="p"
			value={message}
			onChange={(value) => {
				setAttributes({ message: value });
			}}
		/>
	);

save.jsからも<div>を除去して行きます。

import { RichText, useBlockProps } from "@wordpress/block-editor";

export default function save({ attributes }) {
	const { message } = attributes;

	return (
		<RichText.Content
			{...useBlockProps.save()}
			tagName="p"
			value={message}
		/>
	);
}

エディターのマークアップ

<p lass="wp-block-create-block-my-block">
  test
</p>

フロントエンドのマークアップ。

<p class="wp-block-create-block-my-block">
  test
</p>

マークアップの統一が完了しました。

HTMLタグのエスケープを回避

RichTextコンポーネントを使用しない場合、save関数がHTMLタグをエスケープしているため、エディターで太字にすると、フロントエンドではタグがぞのまま表示される。
Hello <strong>Gutrnberg!</strong>

save.jsでRichTextコンポーネントを使用すれば問題ない。

import { __ } from "@wordpress/i18n";
import { RichText, useBlockProps } from "@wordpress/block-editor";

export default function save({ attributes }) {
	const { message } = attributes;

	// return <p {...useBlockProps.save()}>{message}</p>;
	return (
		// 大文字始まりの.Contentを追加
		<RichText.Content
			// .saveを追加
			{...useBlockProps.save()}
			tagName="p"
			value={message}
			// save関数はマークアップを定義するのみのため、onChangeの使用機会はない
			// onChange={(value) => {
			// 	setAttributes({ message: value });
			// }}
		/>
	);
}

block.jsonを編集

htmlタグを認識させるため、block.jsonを確認する。

	"attributes": {
		"message": {
			"type": "string",
			"default": "Hello WordPress!",
			"source": "text"
		}
	},

修正する。

	"attributes": {
		"message": {
			"type": "string",
			"default": "Hello WordPress!",
			"source": "html"
		}
	},

さらに修正する。

	"attributes": {
		"message": {
			"type": "string",
			"default": "Hello WordPress!",
			"source": "html",
			"selector": "p"
		}
	},

プレースホルダーを表示

edit.js

	return (
		<RichText
			{...useBlockProps()}
			tagName="p"
			placeholder="Enter text..."
			value={message}
			onChange={(value) => {
				setAttributes({ message: value });
			}}
		/>
	);

インライン装飾の使用を制限

edit.js

allowedFormatsに空の配列を渡すとインライン装飾が使用できなくなる。

	return (
		<RichText
			{...useBlockProps()}
			tagName="p"
			allowedFormats={[]}
			placeholder="Enter text..."
			value={message}
			onChange={(value) => {
				setAttributes({ message: value });
			}}
		/>
	);

太字・斜体のみ許可

	return (
		<RichText
			{...useBlockProps()}
			tagName="p"
			allowedFormats={["core/bold", "core/italic"]}
			placeholder="Enter text..."
			value={message}
			onChange={(value) => {
				setAttributes({ message: value });
			}}
		/>
	);

実験的な機能追加

コアにマージ未実装の段階で、実験的な機能をブロックに追加する。block.jsonを編集して、カスタムブロックにボーダーコントロールを実装する例。

"supports": {
	"html": false,
	"__experimentalBorder": {
		"width": true,
		"color": true,
		"style": true
	},

参考