ダイナミックブロック ピックアップ記事ブロック作成

ブロックのテンプレートを作詞

my-custom-blocks/srcにpick-up-articleフォルダを作成

block.json

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "my-custom-blocks/pick-up-article",
	"title": "ピックアップ記事",
	"description": "ピックアップ記事です",
	"category": "text",
	"attributes": {},
	"textdomain": "my-custom-blocks",
	"editorScript": "file:./index.js",
	"style": "file:./style-index.css"
}

index.js

import { registerBlockType } from "@wordpress/blocks";

import Edit from "./edit.js";
import metadata from "./block.json";

registerBlockType(metadata.name, {
	edit: Edit,
});

edit.js

export default function Edit() {
	return <>ピックアップ記事</>;
}

index.php

<?php

function my_custom_block_pick_up_article_render_callback(){
	return '<p>render_callbackで実行される関数</p>';
}

function my_custom_block_register_block_pick_up_article(){
	register_block_type(
		__DIR__,
		array(
			'render_callback'=>'my_custom_block_pick_up_article_render_callback'
		)
	);
}
add_action('init', 'my_custom_block_register_block_pick_up_article');

my-custom-blocks.php

function create_block_my_custom_blocks_block_init() {
	register_block_type( __DIR__ . '/build/balloon' );
}
add_action( 'init', 'create_block_my_custom_blocks_block_init' );

//追記
require plugin_dir_path(__FILE__). 'build/pick-up-article/index.php';

ビルド npm run build

index.phpがビルドに含まれないので、package.jsonを編集し、–webpack-copy-phpを追加

"scripts": {
		"build": "wp-scripts build --webpack-copy-php"
		"start": "wp-scripts start --webpack-copy-php",
	},

再ビルドし、エディターにブロックが読み込まれていることを確認する

エディターには「ピックアップ記事」と表示される。
フロントエンドには「render_callbackで実行される関数」が表示される。

エディター画面を作成

edit.js

import { useBlockProps, InspectorControls } from "@wordpress/block-editor";
import ServerSideRender from "@wordpress/server-side-render";
import { useSelect } from "@wordpress/data";
import { PanelBody, BaseControl } from "@wordpress/components";

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

	// サイドパネルに記事のIDを保存機能を追加する
	// WordPressのデータから保存記事リストを取得
	const post = useSelect((select) => {
		return select("core").getEntityRecords("postType", "post");
	}, []);

	console.log("post:", post);

	return (
		<>
			<div {...useBlockProps()}>
				{/* フロント表示と合わせるため、ServerSideRenderを呼び出す */}
				{/* blockには対象のブロック名をblock.jsonより転記する */}
				<ServerSideRender block="my-custom-blocks/pick-up-article" />
			</div>
		</>
	);
}
import { useBlockProps, InspectorControls } from "@wordpress/block-editor";
import ServerSideRender from "@wordpress/server-side-render";
import { useSelect } from "@wordpress/data";
import { PanelBody, BaseControl } from "@wordpress/components";

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

	// サイドパネルに記事のIDを保存機能を追加する
	// WordPressのデータから保存記事リストを取得
	const post = useSelect((select) => {
		return select("core").getEntityRecords("postType", "post");
	}, []);

	console.log("post:", post);

	return (
		<>
			<InspectorControls>
				<PanelBody title="設定">
					<BaseControl>
						{/* postがnullの場合エラーのなるため、lengthのチェックを挟む */}
						{post?.length &&
							// map関数:与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成
							post.map((page) => (
								<div key={page.id}>{page.title.rendered}</div>
							))}
					</BaseControl>
				</PanelBody>
			</InspectorControls>

サイドパネルに記事選択用のチェックボックスを作成

edit.js

import { PanelBody, BaseControl, CheckboxControl } from "@wordpress/components";

			<InspectorControls>
				<PanelBody title="設定">
					<BaseControl>
						{/* postがnullの場合エラーのなるため、lengthのチェックを挟む */}
						{post?.length &&
							// map関数:与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成
							post.map((page) => (
								<div key={page.id}>
									{/* {page.title.rendered} */}
									<CheckboxControl
										label={page.title.rendered}
										checked={pickUpArticleIdLists.includes(page.id)}
										onChange={() => {
											const newPickUpArticleIdLists =
												pickUpArticleIdLists.includes(page.id)
													? pickUpArticleIdLists.filter(
															(item) => item !== page.id,
													  )
													: [...pickUpArticleIdLists, page.id];
											setAttributes({
												pickUpArticleIdLists: newPickUpArticleIdLists,
											});
										}}
									/>
								</div>
							))}
					</BaseControl>
				</PanelBody>
			</InspectorControls>

記事の絞り込み機能を追加

edit.js

import {
	PanelBody,
	BaseControl,
	CheckboxControl,
	SearchControl,
} from "@wordpress/components";
import { useState } from "@wordpress/element";

	const [searchTerm, setSearchTerm] = useState();

	// サイドパネルに記事のIDを保存機能を追加する
	// WordPressのデータから保存記事リストを取得
	const post = useSelect(
		(select) => {
			const query = {};
			if (searchTerm) {
				query.search = searchTerm;
			}
			return select("core").getEntityRecords("postType", "post", query);
		},
		[searchTerm],
	);

			<InspectorControls>
				<PanelBody title="設定">
					<BaseControl>
						<SearchControl
							onChange={(value) => setSearchTerm(value)}
							value={searchTerm}
						/>

検索中はローディング画面を表示する

edit.js

import { useBlockProps, InspectorControls } from "@wordpress/block-editor";
import ServerSideRender from "@wordpress/server-side-render";
import { useSelect } from "@wordpress/data";
import {
	PanelBody,
	BaseControl,
	CheckboxControl,
	SearchControl,
	Spinner,
} from "@wordpress/components";
import { useState } from "@wordpress/element";

export default function Edit(props) {
	const { attributes, setAttributes } = props;
	const { pickUpArticleIdLists } = attributes;
	const [searchTerm, setSearchTerm] = useState();

	// サイドパネルに記事のIDを保存機能を追加する
	// WordPressのデータから保存記事リストを取得
	const { post, hasResolved } = useSelect(
		(select) => {
			const query = {};
			if (searchTerm) {
				query.search = searchTerm;
			}
			const selectorArgs = ["postType", "post", query];
			return {
				post: select("core").getEntityRecords(...selectorArgs),
				hasResolved: select("core").hasFinishedResolution(
					"getEntityRecords",
					selectorArgs,
				),
			};
		},
		[searchTerm],
	);

	console.log("post:", post);

	return (
		<>
			<InspectorControls>
				<PanelBody title="設定">
					<BaseControl>
						<SearchControl
							onChange={(value) => setSearchTerm(value)}
							value={searchTerm}
						/>
						{!hasResolved && <Spinner />}
						{hasResolved && post.length === 0 && <div>検索結果なし</div>}
						{/* postがnullの場合エラーのなるため、lengthのチェックを挟む */}
						{hasResolved && post?.length > 0 && (
							// map関数:与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成
							<div
								style={{
									height: "100px",
									overflow: "scroll",
									border: '1px, solid, "eeeeee',
									padding: "1opx",
								}}
							>
								{post.map((page) => (
									<div
										key={page.id}
										style={{
											padding: "8px 10px 0",
											borderBottom: "1px, solid #cccccc",
										}}
									>
										{/* {page.title.rendered} */}
										<CheckboxControl
											label={page.title.rendered}
											checked={pickUpArticleIdLists.includes(page.id)}
											onChange={() => {
												const newPickUpArticleIdLists =
													pickUpArticleIdLists.includes(page.id)
														? pickUpArticleIdLists.filter(
																(item) => item !== page.id,
														  )
														: [...pickUpArticleIdLists, page.id];
												setAttributes({
													pickUpArticleIdLists: newPickUpArticleIdLists,
												});
											}}
										/>
									</div>
								))}
							</div>
						)}
					</BaseControl>
				</PanelBody>
			</InspectorControls>
			<div {...useBlockProps()}>
				{/* フロント表示と合わせるため、ServerSideRenderを呼び出す */}
				{/* blockには対象のブロック名をblock.jsonより転記する */}
				<ServerSideRender block="my-custom-blocks/pick-up-article" />
			</div>
		</>
	);
}

レンダリングコンテンツの作成

index.php

<?php

function my_custom_block_pick_up_article_render_callback($attributes){
	$pick_up_articles_id_lists = isset($attributes['pickUpArticleIdLists'])? $attributes['pickUpArticleIdLists'] : array();

	if(empty($pick_up_articles_id_lists)){
		return null;
	}

$query = new WP_Query();
$posts = $query->query(
	array(
		'post_type' => 'post',
		'orderby'=> 'post__in',
		'post__in' => $pick_up_articles_id_lists,
		)
	);

	$pick_up_article_html = '';

foreach ($posts as $post){
	$post_link = esc_url(get_permalink($post));
	$title = get_the_title($post);
	$featured_image = get_the_post_thumbnail($post, 'post-thumbnail');

	if(!$title){
		$title = 'タイトルなし';
	}

	$pick_up_article_html .= '<div class"my-custom-blocks-pick-up-article">';
	if($featured_image) {
		$pick_up_article_html .= sprintf(

	'<div class="my-custom-blocks-pick-up-image"><a href="%1$s">%2$s</a></div>',
	$post_link,
	$featured_image
		);
	}

	$pick_up_article_html .= sprintf(
		'<h3 class="my-custom-blocks-pick-up-title"><a href="%1$s">%2$s</a></h3>',
		$post_link,
		$title
	);

	$pick_up_article_html .= '</div>';
};

wp_reset_postdata();

	return $pick_up_article_html;
}

function my_custom_block_register_block_pick_up_article(){
	register_block_type(
		__DIR__,
		array(
			'render_callback'=>'my_custom_block_pick_up_article_render_callback'
		)
	);
}
add_action('init', 'my_custom_block_register_block_pick_up_article');

edit.js

				<ServerSideRender
					block="my-custom-blocks/pick-up-article"
					attributes={ attributes }
				/>

ブロックにラッパークラスを追加

index.php

	$wrapper_attributes = get_block_wrapper_attributes();

	return sprintf(
		'<div $1$s>%s$s</div>',
		$wrapper_attributes,
		$pick_up_article_html
	);

幅広、全幅をサポート

block.json

	"supports": {
		"align": ["wide", "full"],
		"spacing": {
			"padding": true,
			"margin": true
		}
	},