【WordPressブロック開発】投稿の本文(HTMLコメントのないプレーンな状態)を表示する

フロントエンドと編集画面に投稿のタイトルと本文を表示するブロックを開発する。投稿の本文の取得は無限ループが発生するリスクがあるため、ユーザーが投稿IDを入力する方法に変更した。

ブロック開発

block.json

“usesContext”: [“postId”]を指定し、現在の投稿IDを取得する。

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "create-block/my-get-post",
	"version": "0.1.0",
	"title": "My Get Post",
	"category": "widgets",
	"icon": "smiley",
	"description": "Example block scaffolded with Create Block tool.",
	"example": {},
	"supports": {
		"html": false
	},
	"usesContext": ["postId"],
	"textdomain": "my-get-post",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css",
	"render": "file:./render.php",
	"viewScript": "file:./view.js"
}

うまくいかなかったedit.js 1

  1. コンテキストから投稿IDを取得
    • context: { postId }
  2. 投稿本文の格納先を宣言する
    • const [renderedContent, setRenderedContent] = useState(“”)
  3. 投稿IDが変更された場合は再レンダリングする
    • useEffect()
  4. REST API 経由でデータ取得
    • apiFetch( () => {}, [postId])
  5. renderedContentを更新する
    • setRenderedContent(post.content.rendered)
  6. HTML をそのまま表示する
    • dangerouslySetInnerHTML
import { useBlockProps } from "@wordpress/block-editor";
import apiFetch from "@wordpress/api-fetch";
import { useEffect, useState } from "@wordpress/element";

import "./editor.scss";

export default function Edit({ context: { postId } }) {
	const [renderedContent, setRenderedContent] = useState("");

	useEffect(() => {
		if (postId) {
			apiFetch({ path: `/wp/v2/posts/${postId}` }).then((post) => {
				setRenderedContent(post.content.rendered);
			});
		}
	}, [postId]);

	return (
		<div
			{...useBlockProps()}
			dangerouslySetInnerHTML={{ __html: renderedContent }}
		/>
	);
}

結果、編集画面にもrender.phpの内容が表示されるが、重複読み込みが発生する

編集画面フロントエンド
My Get Postブロックが【これは本文です】と表示
【テストです】も読み込まれる
My Get Postブロックが【これは本文です】と表示
【テストです】も読み込まれる
【テストです】と段落ブロックを挿入

うまくいかなかったedit.js 2

import { useBlockProps } from "@wordpress/block-editor";
import { useEntityProp } from "@wordpress/core-data";
import { select } from "@wordpress/data";

import "./editor.scss";

export default function Edit({ context: { postType, postId } }) {
	const getPostContent = select("core/editor").getEditedPostContent();
	console.log(getPostContent);

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

編集画面の表示はHTMLコメントがそのまま表示されてしまった。

<!-- wp:create-block/my-get-post {"postID":57} /-->

<!-- wp:paragraph -->
<p>ブロックづくり楽しい</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>もっと楽しい!</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list --> 

原因は、getEditedPostContent() を使用していて、それは現在編集中の投稿全体のブロック構成(ブロックコメント付きのHTML)を返しているため。

次に、apply_filtersを通してブロックコメント付きの raw content を 正しくレンダリングされた HTML に変換すると、メモリーオーバーになってしまった。

<?php

$post_id = get_the_ID();
$select_post = get_post($post_id);

if ($select_post) {
	// Gutenbergコメントなども含めたコンテンツをフィルター経由でHTMLに変換
	$content = apply_filters('the_content', $select_post->post_content);
}
?>
<div <?php echo get_block_wrapper_attributes(); ?>>
	<?php echo $content; ?>
</div>

投稿の本文内に該当のブロックが含まれていたため、自己参照のループが発生し、自爆ループとなっていたため。

edit.js 完成

対策として、ユーザーが任意の投稿IDを指定するように改良する

import { useBlockProps } from "@wordpress/block-editor";
import { TextControl } from "@wordpress/components";
import { useSelect } from "@wordpress/data";

import "./editor.scss";

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

	const selectPost = useSelect(
		(select) =>
			postID
				? select("core").getEntityRecord("postType", "post", postID)
				: null,
		[postID],
	);

	return (
		<div {...useBlockProps()}>
			<TextControl
				label="表示したい投稿ID"
				type="number"
				value={postID ?? ""}
				onChange={(newId) =>
					setAttributes({ postID: newId === "" ? null : parseInt(newId, 10) })
				}
			/>

			{selectPost && <p>投稿タイトル:{selectPost.title.rendered}</p>}

			{postID && !selectPost && <p>投稿が見つかりませんでした。</p>}
		</div>
	);
}
  • useSelect:データストアにアクセスしてデータを取得する React Hook
  • getEntityRecord :特定の投稿タイプとIDに対応する投稿データを取得
  • “core” :WordPress の公式ストア(コアデータ)
  • “postType” :投稿やカスタム投稿タイプを取得するための指定

render.php

  • 編集画面で入力した$attributesを受け取る
  • 受取に成功したら、the_contentフックを通して取得した投稿データを表示する
<?php

$post_id = isset($attributes['postID']) ? (int) $attributes['postID'] : 0;
	$content = apply_filters('the_content', $post->post_content);

	printf(
		'<div %s>%s</div>',
		get_block_wrapper_attributes(),
		$content
	);
} else {
	echo '<p>表示する投稿が見つかりません。</p>';
}