2026年8月10日

2026年8月10日

WordPressのInteractivity APIでカスタムブロックを作る|REST APIからデータを取得する例

WordPress のブロックで、ボタンを押したら表示が変わる、サーバーからデータを読み込んで一覧を出す、といった動きを付けたいときは Interactivity API を使います。WordPress 6.5 から本体に入った、ブロックのフロントエンド(公開ページ)側の動きを書くための標準の仕組みです。

この記事では、「最新の投稿を読み込む」ボタンを押すと、WordPress の REST API から投稿を5件取得して一覧を表示するブロックを作ります。手順とコードは2026年10月時点の公式ドキュメントと雛形に合わせています。

Interactivity API の仕組み

Interactivity API は、次の2つを組み合わせて動きます。

場所 書くもの 例
render.php(サーバー側の HTML) data-wp- で始まる属性(ディレクティブ)で、どの要素が何に反応するかを書く data-wp-on--click="actions.loadPosts"
view.js(ブラウザー側) store() で状態(state)・アクション(actions)・コールバックを定義する actions.loadPosts の中身
  • data-wp-interactive="名前空間" を付けた要素とその子要素が、Interactivity API の対象になります。
  • data-wp-context は、その要素の範囲だけで使うデータ(コンテキスト)です。PHP では wp_interactivity_data_wp_context() で出力します。
  • サーバーで最初の HTML がディレクティブどおりに描画されるため、JavaScript が動く前でも初期表示が出ます。

準備

  • WordPress 6.5 以上(6.4 以前は Gutenberg プラグイン 17.5 以上が必要)
  • Node.js と npm。2026年10月時点の @wordpress/create-block の説明では、Node.js 22.13.0 以上が必要とされています。
  • ローカルの WordPress 環境(プラグインフォルダーで作業できること)

ステップ1: 雛形を作る

wp-content/plugins で次のコマンドを実行します。Interactivity API 用の公式テンプレートを使い、名前空間を myplugin にします。

cd wp-content/plugins
npx @wordpress/create-block@latest recent-posts-viewer --namespace=myplugin --template @wordpress/create-block-interactive-template
cd recent-posts-viewer

src/recent-posts-viewer/ に block.json・render.php・view.js・edit.js などが作られます。block.json には、テンプレートによって次の設定が入っています。

{
	"supports": {
		"interactivity": true
	},
	"viewScriptModule": "file:./view.js",
	"render": "file:./render.php"
}
  • supports.interactivity: このブロックが Interactivity API を使うことを示します。
  • viewScriptModule: 公開ページで読み込む JavaScript を、ES モジュールとして読み込みます。
  • render: 公開ページの HTML を PHP で出力します(ダイナミックブロック)。

package.json のビルドコマンドにも、モジュールを扱うための --experimental-modules がテンプレートで付けられています。

ステップ2: render.php を書き換える

src/recent-posts-viewer/render.php を次の内容にします。REST API の URL は PHP で作って wp_interactivity_config() でブラウザー側に渡し、表示用のデータはコンテキストに持たせます。

<?php
/**
 * 公開ページでの表示。$attributes, $content, $block が使える。
 */

wp_interactivity_config(
	'myplugin',
	array(
		'postsUrl' => esc_url_raw(
			add_query_arg(
				array(
					'per_page' => 5,
					'_fields'  => 'id,link,title',
				),
				rest_url( 'wp/v2/posts' )
			)
		),
	)
);

$context = array(
	'posts'   => array(),
	'loading' => false,
	'error'   => '',
);
?>
<div
	<?php echo get_block_wrapper_attributes(); ?>
	data-wp-interactive="myplugin"
	<?php echo wp_interactivity_data_wp_context( $context ); ?>
>
	<button
		type="button"
		data-wp-on--click="actions.loadPosts"
		data-wp-bind--disabled="context.loading"
	>
		<?php esc_html_e( '最新の投稿を読み込む', 'recent-posts-viewer' ); ?>
	</button>

	<p data-wp-bind--hidden="!context.loading">
		<?php esc_html_e( '読み込み中…', 'recent-posts-viewer' ); ?>
	</p>

	<p data-wp-bind--hidden="!context.error" data-wp-text="context.error"></p>

	<ul>
		<template data-wp-each--post="context.posts" data-wp-each-key="context.post.id">
			<li><a data-wp-bind--href="context.post.link" data-wp-text="context.post.title"></a></li>
		</template>
	</ul>
</div>

使っているディレクティブは次のとおりです。

ディレクティブ 働き
data-wp-on--click クリックされたらアクションを呼ぶ
data-wp-bind--属性名 値に応じて HTML の属性を付け外しする(! を付けると真偽を反転)
data-wp-text 要素の中の文字を値で置き換える
data-wp-each--名前 配列の要素ごとに <template> の中身を繰り返す。各要素は context.名前 で参照する
data-wp-each-key 繰り返す要素を見分けるキー。要素がオブジェクトのときは <template> に付ける

?per_page= を URL の末尾に文字列で足すと、パーマリンクが「基本」のサイト(REST API の URL が ?rest_route= の形になる)で壊れます。add_query_arg() で組み立てておくと、どちらの形でも動きます。

ステップ3: view.js を書き換える

src/recent-posts-viewer/view.js を次の内容にします。

import { store, getContext, getConfig } from '@wordpress/interactivity';

// REST API の title.rendered は HTML 実体参照を含むことがあるので、文字に戻す
const decodeHtml = ( html ) =>
	new DOMParser().parseFromString( html, 'text/html' ).documentElement.textContent;

store( 'myplugin', {
	actions: {
		*loadPosts() {
			const context = getContext();
			const { postsUrl } = getConfig( 'myplugin' );

			context.loading = true;
			context.error = '';

			try {
				const posts = yield fetch( postsUrl ).then( ( response ) => {
					if ( ! response.ok ) {
						throw new Error( `HTTP ${ response.status }` );
					}
					return response.json();
				} );

				context.posts = posts.map( ( post ) => ( {
					id: post.id,
					link: post.link,
					title: decodeHtml( post.title.rendered ),
				} ) );
			} catch ( error ) {
				context.error = '投稿を読み込めませんでした。';
			} finally {
				context.loading = false;
			}
		},
	},
} );

要点は次のとおりです。

  • 非同期のアクションはジェネレーター関数(*loadPosts())で書き、await の代わりに yield を使います。 公式ドキュメントでは、async/await ではなくジェネレーターを使うよう案内されています。yield のあとでも getContext() で得たコンテキストが正しいブロックのものとして扱われます。
  • context の値を書き換えると、render.php のディレクティブに従って表示が自動で更新されます。DOM を直接操作するコードは書きません。
  • event.preventDefault() などイベントを同期的に扱うアクションは、WordPress 6.8 以降 withSyncEvent() で包む必要があります。この例のアクションはイベントを使わないので不要です。

ステップ4: ビルドして動かす

npm run build
wp plugin activate recent-posts-viewer

WP-CLI を使わない場合は、管理画面の「プラグイン」で、作成したプラグインを有効化します。投稿か固定ページの編集画面でブロックを追加し、公開ページでボタンを押して一覧が出ることを確かめます。開発中は npm start にすると、ファイルを保存するたびにビルドされます。

ブロックエディターの中の表示は edit.js が担当し、Interactivity API の動きは公開ページでだけ働きます。エディターでも同じ一覧を見せたい場合は、edit.js 側で @wordpress/api-fetch や useSelect を使って別に書きます。

うまく動かないとき

症状 確かめること
ボタンを押しても何も起きない data-wp-interactive と store() の名前空間(ここでは myplugin)が一致しているか。npm run build 後の build/ が読み込まれているか
ブラウザーのコンソールに getConfig などの読み込みエラーが出る WordPress が 6.5 以上か。block.json が viewScript ではなく viewScriptModule になっているか
「投稿を読み込めませんでした。」と出る ブラウザーの開発者ツールのネットワーク欄で REST API の応答を確認する。REST API を制限するプラグインや設定で /wp/v2/posts が止められていないか
文字の中に &#8217; などが出る title.rendered をそのまま入れていないか(例の decodeHtml() を通す)

REST API がエラーを返す場合は WordPress REST APIのエラーの直し方 も参考にしてください。

外部の API を使う場合の注意

天気やニュースなど外部サービスの API を使う場合も、考え方は同じです。ただし次の点に気を付けます。

  • API キーをブラウザー側に置かない: view.js や wp_interactivity_config() に書いた値は、訪問者が誰でも見られます。キーが必要な API は、PHP 側で wp_remote_get() を使って取得するか、自前の REST API エンドポイントを中継にします。
  • 取得結果をキャッシュする: 外部 API には回数制限があることが多いため、PHP 側で取得した結果を Transients API などで一定時間保存し、ページごと・訪問者ごとに外部へ問い合わせないようにします。
  • CORS: ブラウザーから別のドメインの API を直接呼ぶ場合、相手のサーバーが CORS を許可していないと読み込めません。この場合も PHP 側で取得するのが現実的です。
  • 取得するデータを絞る: この例の _fields のように、必要な項目だけを要求すると転送量が減ります。

まとめ

  • ブロックのフロントエンドの動きは、WordPress 6.5 以降の Interactivity API で書けます。
  • 雛形は npx @wordpress/create-block@latest スラッグ --template @wordpress/create-block-interactive-template で作ります。
  • render.php にディレクティブ、view.js に store() を書き、非同期の処理はジェネレーター関数と yield で書きます。
  • サーバー側で作った値は wp_interactivity_config() やコンテキストで渡し、秘密の値はブラウザーに出さないようにします。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲