株式会社HAMWORKS
🤔

【WordPress】指定した期間までNEWマークを出すブロックを作ってみる

2024/04/25に公開

習作シリーズ(?)です。

create-blockをする

https://ja.wordpress.org/team/handbook/block-editor/reference-guides/packages/packages-create-block/

block.jsonを用意する

NEWアイコンにつけるCSSはすべてブロックのCSSで完結させます。
なので、supportsで色やフォントサイズ、余白を有効にします。

attributesは、NEW用に表示するテキストと、NEWを表示させる期間をもたせておきます。

block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "chiilog-block/new-icon",
	"version": "0.1.0",
	"title": "New Icon Block",
	"category": "text",
	"icon": "smiley",
	"example": {},
	"supports": {
		"html": false,
		"align": true,
		"color": {
			"gradients": true,
			"background": true,
			"text": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true
		},
		"spacing": {
			"padding": true,
			"margin": true
		}
	},
	"attributes": {
		"text": {
			"type": "string",
			"default": "NEW"
		},
		"period": {
			"type": "number",
			"default": "7"
		}
	},
	"usesContext": [ "postType", "postId" ],
	"textdomain": "new-icon",
	"editorScript": "file:./index.js",
	"render": "file:./render.php"
}

edit.tsxを用意

またもやベース風味なものを用意します。

edit.tsx
type BlockAttributes = {
	text: string;
	period: number;
};

export default function Edit( {
	attributes: { text, period },
	setAttributes,
}: BlockEditProps< BlockAttributes > ) {
	const blockProps = useBlockProps();

	return (
		<div { ...blockProps }>
			<RichText
				value={ text }
				onChange={ ( value ) => {
					setAttributes( { text: value } );
				} }
			/>
		</div>
	);
}

このNEWアイコンは編集画面では出しっぱなしにするので、(消えると編集できなくなってしまうので)RichTextまわりはこのまま出すことにします。
次に、periodの設定パネルをつけます。

periodnumberだよ、という型を定義しているので、NumberControlを使ってみたいところではありますが、これはまだ__experimentalNumberControlとのこと。

https://developer.wordpress.org/block-editor/reference-guides/components/number-control/

まだ実験段階であれば、実際の案件では使うのは控えた方がいいですね。というわけで、この練習でもTextControl を使うことにします。

https://developer.wordpress.org/block-editor/reference-guides/components/text-control/

edit.tsx
type BlockAttributes = {
	text: string;
	period: number;
};

export default function Edit( {
	attributes: { text, period },
	setAttributes,
}: BlockEditProps< BlockAttributes > ) {
	const blockProps = useBlockProps();

	return (
		<>
+			<TextControl
+				label="Period to display Text"
+				value={ period }
+				onChange={ ( value ) => setAttributes({ period: value } ) }
+			/>
			<div { ...blockProps }>
				<RichText
					value={ text }
					onChange={ ( value ) => {
						setAttributes( { text: value } );
					} }
				/>
			</div>
		</>
	);
}

TextControlvaluestring型なので、型やblock.jsonを修正します。

block.json
{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "chiilog-block/new-icon",
	"version": "0.1.0",
	"title": "New Icon Block",
	"category": "text",
	"icon": "smiley",
	"example": {},
	"supports": {
		"html": false,
		"align": true,
		"color": {
			"gradients": true,
			"background": true,
			"text": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true
		},
		"spacing": {
			"padding": true,
			"margin": true
		}
	},
	"attributes": {
		"text": {
			"type": "string",
			"default": "NEW"
		},
		"period": {
-			"type": "number",
+			"type": "string",
			"default": "7"
		}
	},
	"usesContext": [ "postType", "postId" ],
	"textdomain": "new-icon",
	"editorScript": "file:./index.js",
	"render": "file:./render.php"
}
edit.tsx
type BlockAttributes = {
	text: string;
-	period: number;
+	period: string;
};

...

ここがnumber型のままだと、TextControlでうまく値が更新されなくなります。string型なので数字以外も入ってしまいますが、ここはrender.phpでカバーすることにします。

このままだと

こんな感じで入力エリアにTextControlが表示されてしまいます。これは右の設定パネルにいれたいので、InspectorControlsPanelBodyを追加します。

https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inspector-controls/README.md

https://developer.wordpress.org/block-editor/reference-guides/components/panel/

edit.tsx
export default function Edit( {
	attributes: { text, period },
	setAttributes,
}: BlockEditProps< BlockAttributes > ) {
	const blockProps = useBlockProps();

	return (
		<>
+			<InspectorControls>
+				<PanelBody
+					title="Settings"
+					initialOpen={ true }
+				>
+					<TextControl
+						label="Period to display Text"
+						value={ period }
+						onChange={ ( value ) =>
+							setAttributes( { period: value } )
+						}
+					/>
+				</PanelBody>
+			</InspectorControls>
-			<TextControl
-    			label="Period to display Text"
-    			value={ period }
-    			onChange={ ( value ) =>
-        			setAttributes( { period: value } )
-    			}
-			/>
			<div { ...blockProps }>
				<RichText
					value={ text }
					onChange={ ( value ) => {
						setAttributes( { text: value } );
					} }
				/>
			</div>
		</>
	);
}

こんな感じになりました!
あとはrender.phpを作っていきます。

render.phpを用意

render.php
<?php
/**
 * @var array $attributes The block attributes.
 * @var string $content The block content.
 * @var WP_Block $block The block object.
 *
 * @see https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#render
 */

// 期間を取得。ここで半角に変換しておく
$period = mb_convert_kana( $attributes['period'], 'n', 'UTF-8' );

// 期間が数値でない場合はデフォルト値をセット
if ( ! is_numeric( $period ) ) {
	$period = 7;
}

// 投稿日から指定日数後の日付を取得
$post_date    = new DateTime( get_the_date( 'Y-m-d' ) );
$post_date->modify( '+' . $period . ' days' );

// 今日の日付
$current_date = new DateTime();

if ( $post_date >= $current_date ) :
	?>
	<div <?php echo get_block_wrapper_attributes(); ?>>
		<?php echo esc_html( $attributes['text'] ); ?>
	</div>
	<?php
endif;

TextControlstring型なので、全角数字やそもそも数字以外が入ったときの処理を入れておきます。ありがちなミスとして全角数字があるかなーと思ったので、mb_convert_kanaで事前に半角に変換してからif文に入れます。

これでNEWマークを出すことはできましたが、PhpStormで「未処理の\Exception」というエラーが出ます🤔
ヒントに「try-catchで囲む」と出たので調べてみました。

https://www.php.net/manual/ja/language.exceptions.php

PhpStorm的にnew DateTime( get_the_date( 'Y-m-d' ) )が例外投げられるんじゃね?という心配をしてくれた模様?

というわけで、render.phpの中身はこうなりました。

$content = '<div ' . get_block_wrapper_attributes() . '>' . esc_html( $attributes['text'] ) . '</div>';

try {
	// 期間を取得。ここで半角に変換しておく
	$period = mb_convert_kana( $attributes['period'], 'n', 'UTF-8' );

	// 期間が数値でない場合はデフォルト値をセット
	if ( ! is_numeric( $period ) ) {
		$period = 7;
	}

	// 投稿日から指定日数後の日付を取得
	$post_date    = new DateTime( get_the_date( 'Y-m-d' ) );
	$post_date->modify( '+' . $period . ' days' );

	// 今日の日付
	$current_date = new DateTime();

	if ( $post_date >= $current_date ) :
		echo wp_kses_post( $content );
	endif;
} catch ( Exception $e ) {
	echo wp_kses_post( $content );
}

まとめ

編集画面はこんな感じで、背景色や文字色も変えられます。
表示画面も値がきちんと適用されています。

指定した期間が過ぎた場合は、編集画面はそのままに表示側では消えてしまいます。

アーカイブテンプレートでもこのように配置して、

表示はこの通り。
※Hello world!で表示させるために日付変更

こういうのすでにプラグインディレクトリにありそうだなーと思ってプラグインディレクトリで検索かけてみたんですが、意外とありませんでした。……が、探し方が悪いだけかも。こういうNEWマーク、っていうか期間絞って表示するブロックってどう検索するのがいいのかなあ🤔

今回作ったブロックはGitHubにあげています。フルでコード見たい方はどうぞ。

https://github.com/chiilog/new-icon-block

株式会社HAMWORKS
株式会社HAMWORKS

Discussion