【WordPressブロック開発】アコーディオンブロックを作成しよう

WordPressでアコーディオンブロックを作成してみます。複数のattributesをエディターUIで使い分けるようにblock.jsonに設定を追加する点がポイントです。

プラグインの雛形を作成

プラグインディレクトリでコマンド実行

npx @wordpress/create-block my-block
cd todo-list
npm start

プラグイン作成

edit.jsを編集、<details>タグを追加

export default function Edit() {
	return (
		<details>
			<summary>システム要件</summary>
			<p>
				オペレーティングシステムを実行するコンピューターが必要です。コンピューターにはメモリーがあり、できれば何らかの長期保存用の記憶装置があること。入力機器と何らかの出力機器を推奨。
			</p>
		</details>
	);

	// return (
	// 	<p {...useBlockProps()}>
	// 		{__("Dojo Block – hello from the editor!", "dojo-block")}
	// 	</p>
	// );
}

ブロックとして認識されないため、インライン装飾が有効化していない。

ブロックとして認識されるためには{…useBlockProps()}が必要

export default function Edit() {
	return (
		<details {...useBlockProps()}>
			<summary>システム要件</summary>
			<p>
				オペレーティングシステムを実行するコンピューターが必要です。コンピューターにはメモリーがあり、できれば何らかの長期保存用の記憶装置があること。入力機器と何らかの出力機器を推奨。
			</p>
		</details>
	);
}

ブロックとして認識され、基本機能は完成。ただし、クリックすると閉じてしまうため、編集できない。

エディター側のみ<details>と<summary>タグを<div>に書き換える。フロントは<details>と<summary>のまま。

export default function Edit() {
	return (
		<div {...useBlockProps()}>
			<div>システム要件</div>
			<p>
				オペレーティングシステムを実行するコンピューターが必要です。コンピューターにはメモリーがあり、できれば何らかの長期保存用の記憶装置があること。入力機器と何らかの出力機器を推奨。
			</p>
		</div>
	);
}

CSSクラスを当てる

export default function Edit() {
	return (
		<div {...useBlockProps()}>
			<div className="wp-block-create-block-dojo-block__title">
				システム要件
			</div>
			<p className="wp-block-create-block-dojo-block__content">
				オペレーティングシステムを実行するコンピューターが必要です。コンピューターにはメモリーがあり、できれば何らかの長期保存用の記憶装置があること。入力機器と何らかの出力機器を推奨。
			</p>
		</div>
	);
}

適宜style.scssを編集

edit.jsを編集、RichTextをインポート

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

export default function Edit() {
	return (
		<div {...useBlockProps()}>
			<RichText className="wp-block-create-block-dojo-block__title" />
			<RichText className="wp-block-create-block-dojo-block__content" />
		</div>
	);
}

<div>を<p>でレンダリング、プレースホルダーを追加

export default function Edit() {
	return (
		<div {...useBlockProps()}>
			<RichText
				className="wp-block-create-block-dojo-block__title"
				placeholder="ここにタイトル"
			/>
			<RichText
				className="wp-block-create-block-dojo-block__content"
				placeholder="ここにコンテンツ"
				tagName="p"
			/>
		</div>
	);
}

block.jsonを編集、テキスト保存する

{
	"supports": {
		"html": false
	},
	"attributes": {
		"title": {
			"type": "string",
			"default": "タイトル"
		},
		"content": {
			"type": "string",
			"default": "コンテンツ"
		}
	},
}

attributesを追加、初期値を設定

export default function Edit({ attributes }) {
	const { title, content } = attributes;
	return (
		<div {...useBlockProps()}>
			<RichText
				className="wp-block-create-block-dojo-block__title"
				placeholder="ここにタイトル"
				value={title}
			/>
			<RichText
				className="wp-block-create-block-dojo-block__content"
				placeholder="ここにコンテンツ"
				tagName="p"
				value={content}
			/>
		</div>
	);
}

コンテンツを監視し変化があった時にデフォルト値を更新する

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

export default function Edit({ attributes, setAttributes }) {
	const { title, content } = attributes;
	return (
		<div {...useBlockProps()}>
			<RichText
				className="wp-block-create-block-dojo-block__title"
				placeholder="ここにタイトル"
				value={title}
				onChange={(value) => {
					setAttributes({ title: value });
				}}
			/>
			<RichText
				className="wp-block-create-block-dojo-block__content"
				placeholder="ここにコンテンツ"
				tagName="p"
				value={content}
				onChange={(value) => {
					setAttributes({ content: value });
				}}
			/>
		</div>
	);
}

更新ボタンが活性化する

save.jsに保存処理を書く

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

export default function save({ attributes }) {
	const { title, content } = attributes;
	return (
		<details {...useBlockProps.save()}>
			<RichText.Content
				className="wp-block-create-block-dojo-block__title"
				tagName="summary"
				value={title}
			/>
			<RichText.Content
				className="wp-block-create-block-dojo-block__content"
				tagName="p"
				value={content}
			/>
		</details>
	);
}

開いているときは、アイコンを横線のみにする

.wp-block-create-block-dojo-block {
	background-color: #ccc;
	border-radius: 8px;
	padding: 0.5em;

	&[open] .wp-block-create-block-dojo-block__title::after {
		display: none;
	}
}

ブロックサポートを有効化

block.jsonを編集、コードエディタのコメントを削除

{
	"supports": {
		"html": false,
		"color": {
			"background": true,
			"text": true
		}
	},
	"attributes": {
		"title": {
			"type": "string",
			"default": "タイトル",
			"selector": "wp-block-create-block-dojo-block__title",
			"source": "html"
		},
		"content": {
			"type": "string",
			"default": "コンテンツ",
			"selector": "wp-block-create-block-dojo-block__content",
			"source": "html"
		}
	},
}

完成したソース

block.json

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "create-block/my-block",
	"version": "0.1.0",
	"title": "My Block",
	"category": "widgets",
	"icon": "smiley",
	"description": "Example block scaffolded with Create Block tool.",
	"example": {},
	"supports": {
		"html": false,
		"color": {
			"background": true,
			"text": true
		}
	},
	"attributes": {
		"title": {
			"type": "string",
			"default": "タイトル",
			"selector": "wp-block-create-block-my-block__title",
			"source": "html"
		},
		"content": {
			"type": "string",
			"default": "コンテンツ",
			"selector": "wp-block-create-block-my-block__content",
			"source": "html"
		}
	},
	"textdomain": "my-block",
	"editorScript": "file:./index.js",
	"style": "file:./style-index.css"
}

edit.js

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

export default function Edit({ attributes, setAttributes }) {
	const { title, content } = attributes;

	return (
		<>
			{/* <div {...blockProps()}>
				<InspectorControls>Sidebar</InspectorControls>
			</div> */}
			<div {...useBlockProps()}>
				<RichText
					className="wp-block-create-block-my-block__title"
					placeholder="ここにタイトル"
					value={title}
					onChange={(value) => {
						setAttributes({ title: value });
					}}
				/>
				<RichText
					className="wp-block-create-block-dojo-block__content"
					placeholder="ここにコンテンツ"
					tagName="p"
					value={content}
					onChange={(value) => {
						setAttributes({ content: value });
					}}
				/>
			</div>
		</>
	);
}

save.js

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

export default function save({ attributes }) {
	const { title, content } = attributes;
	return (
		<details {...useBlockProps.save()}>
			<RichText.Content
				className="wp-block-create-block-my-block__title"
				tagName="summary"
				value={title}
			/>
			<RichText.Content
				className="wp-block-create-block-my-block__content"
				tagName="p"
				value={content}
			/>
		</details>
	);
}

sty;e.scss

.wp-block-create-block-my-block {
	background-color: #ccc;
	border-radius: 8px;
	padding: 0.5em;

	&[open] .wp-block-create-block-my-block__title::after {
		display: none;
	}
}