【wordpress】自作ブロックの背景色と文字色をクラスのある場合とインラインの場合で切り替える方法

wordpress

wordpressでReactを使ってブロックエディタ「Gutenberg」の自作ブロックを作成したときに、
背景色と文字色をクラスのある場合とインラインの場合で切り替える方法を紹介します。
カラーピッカーで自由に選択された場合、クラス名はなくインラインになりますが、
editor-color-paletteの指定色を使用した場合、クラス名が生成されますので、クラス名がある場合は、極力インラインを無効化したいです。
そのときにwithColorsという高階コンポーネント (higher-order component; HOC)でコンポーネントをラップしてあげることで可能になります。

【グーテンベルグ】背景色と文字色をクラスのある場合とインラインの場合で切り替える方法(色のみ使用可能)

block.jsonのsupportsに以下をcolorを追加するだけで実装可能です。

	"supports": {
		"html": false,
		"color": {
			"background": true,
			"text": true
		}
	},

ただし、これは背景色や文字色など色のみ可能な方法で、その他のcssは以下の方法でやる必要があります。

デフォルトのカスタムカラーを指定しておきたいときは、コードエディタ画面でプロパティをチェックします。
オブジェクトでデリミターに記述があるので、
それをblock.jsonで指定してあげればデフォルトの色を指定することができます。
たとえば下のような感じです。

		"style": {
			"type": "object",
			"default": {
				"color": {
					"background": "#ff3300"
				}
			}
		}

【グーテンベルグ】背景色と文字色をクラスのある場合とインラインの場合で切り替える方法(他のプロパティでも使用可能)

block.json

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 2,
	"name": "cuctom-block/text-box",
	"version": "0.1.0",
	"title": "カスタムテキストボックス",
	"category": "text",
	"icon": "text-page",
	"description": "カスタムテキストボックスです。",
	"keywords": [ "text", "paragraph", "box", "テキスト", "文章", "ボックス" ],
	"supports": {
		"html": false
	},
	"textdomain": "text-box",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css",
	"attributes": {
		"text": {
			"type": "string",
			"source": "html",
			"selector": "h4"
		},
		"alignment": {
			"type": "string",
			"default": "left"
		},
		"backgroundColor": {
			"type" : "string"
		},
		"textColor": {
			"type" : "string"
		},
		"customBackgroundColor": {
			"type" : "string"
		},
		"customTextColor": {
			"type" : "string"
		}
	}
}

ポイントは、backgroundColorとtextColorの他に、customBackgroundColorとcustomTextColorを用意します。
backgroundColorとtextColorでは、functions.phpで設定したeditor-color-paletteから色を取得した色のときに使われる変数です。
customBackgroundColorとcustomTextColorは、カラーピッカーで自由に選択された場合の変数です。自由に選択された場合、クラス名はなくインラインになりますが、
editor-color-paletteの指定色を使用した場合、クラス名が生成されますので、クラス名がある場合は、極力インラインを無効化したいです。

edit.js

import { __ } from '@wordpress/i18n';
// InspectorControlsはブロック選択したときのサイドバー部分
import {
	useBlockProps,
	RichText,
	BlockControls,
	InspectorControls,
	AlignmentToolbar,
	PanelColorSettings,
	ContrastChecker,
	withColors,
} from '@wordpress/block-editor';

import './editor.scss';

function Edit( props ) {
	const {
		attributes,
		setAttributes,
		backgroundColor,
		textColor,
		setBackgroundColor,
		setTextColor,
	} = props;
	// console.log( attributes,props );
	
	// attributesはblock.jsonで定義したattributes
	const { text, alignment } = attributes;
	const onChangeText = ( newText ) => {
		setAttributes( { text: newText } );
	};
	const onChangeAlignment = ( newAligment ) => {
		setAttributes( { alignment: newAligment } );
	};

	return (
		<>
			<InspectorControls>
				{ /* functions.phpで設定したeditor-color-paletteから色を取得する */ }
				<PanelColorSettings
					title={ __( '色の設定', 'text-box' ) }
					icon="admin-appearance"
					initialOpen
					disableCustomColors={ false }
					colorSettings={ [
						{
							value: backgroundColor.color,
							onChange: setBackgroundColor,
							label: __( '背景色', 'text-box' ),
						},
						{
							value: textColor.color,
							onChange: setTextColor,
							label: __( '文字色', 'text-box' ),
						},
					] }
				>
					<ContrastChecker
						textColor={ textColor.color }
						backgroundColor={ backgroundColor.color }
					/>
				</PanelColorSettings>
			</InspectorControls>
			<BlockControls>
				<AlignmentToolbar
					onChange={ onChangeAlignment }
					value={ alignment }
				/>
			</BlockControls>
			<RichText
				{ ...useBlockProps( {
					className: `text-box-align-${ alignment }`,
					style: {
						backgroundColor: backgroundColor.color,
						color: textColor.color,
					},
				} ) }
				onChange={ onChangeText }
				value={ text }
				placeholder={ __( '入力してください。', 'text-box' ) }
				tagName="h4"
			/>
		</>
	);
}


export default withColors( {
	backgroundColor: 'backgroundColor',
	textColor: 'color',
} )( Edit );

withColorsという高階コンポーネント (higher-order component; HOC)を使ってEditコンポーネントをラップすることでinline cssではなくクラス名がpropsで取得できるようになるので、クラス名から色を適用できます。
withColorsは関数で他の関数を返す。その引数としてEditコンポーネントを指定します。
export default withColors()( Edit );
このようなカタチです。
withColorsでラップすることで、propsにsetBackgroundColor、setTextColorといったsetterを取得することができます。
そのため、それをonChangeで指定すれば色を変更できるようになります。
RichText部分でも、オブジェクト形式になっているので、それに合わせてstyle 属性を記述します。

					style: {
						backgroundColor: backgroundColor.color,
						color: textColor.color,
					},

save.js

import {
	useBlockProps,
	RichText,
	getColorClassName,
} from '@wordpress/block-editor';
// classNameを取得するのに必要
// npm i classnames
import classnames from 'classnames';

export default function save( { attributes } ) {
	// custom~はカラーパレットの自由選択で選ばれたとき
	const {
		text,
		alignment,
		backgroundColor,
		textColor,
		customBackgroundColor,
		customTextColor,
	} = attributes;

	// backgroundClassは指定色ならクラスあり、自由選択で選ばれたときはclass名はundefinedになる
	const backgroundClass = getColorClassName(
		'background-color',
		backgroundColor
	);
	const textClass = getColorClassName( 'color', textColor );

	// classnamesは左辺がtrueなら、右辺のクラスを追加できる
	// 追加したい要素がすでにclassNameが指定されている場合、第一引数に指定して、第二引数にclassnamesで判定したいものをいれる。
	const classes = classnames( `text-box-align-${ alignment }`, {
		[ backgroundClass ]: backgroundClass,
		[ textClass ]: textClass,
	} );
	return (
		// RichTextは編集可能なものだけどsave画面では不要なのでContentにする
		<RichText.Content
			{ ...useBlockProps.save( {
				className: classes,
				style: {
					backgroundColor: backgroundClass
						? undefined
						: customBackgroundColor,
					color: textColor ? undefined : customTextColor,
				},
			} ) }
			tagName="h4"
			value={ text }
		/>
	);
}

ポイントは、getColorClassNameでクラス名を取得することと、
classnamesというライブラリでクラスがある場合とない場合で条件分岐することです。

	import classnames from 'classnames';
const classes = classnames( `text-box-align-${ alignment }`, {
		[ backgroundClass ]: backgroundClass,
		[ textClass ]: textClass,
	} );

npm i classnamesでclassnamesをインストールしたあと、インポートして、
上のように使用します。
classnamesは左辺がtrueなら、右辺のクラスを追加できます。
追加したい要素がすでにclassNameが指定されている場合、第一引数に指定して、第二引数にclassnamesで判定したいものをいれます。
追加したい要素にクラス名が特にない場合は、第一引数にオブジェクトを記述します。
あとは、RichTextでクラス名がある場合とない場合で条件分岐されているので、クラス部分はclassName: classes,でOKになります。
スタイル部分はインラインが必要なときとそうでないときと場合分けする必要があるため、以下のように記述して分岐させます。

				style: {
					backgroundColor: backgroundClass
						? undefined
						: customBackgroundColor,
					color: textColor ? undefined : customTextColor,
				},

wordpress

Posted by devsakaso