パッケージインストール
npm プロジェクトの初期化
package.json ファイルを作成します。
npm init -y
@wordpress/scriptsのインストール
(WordPress のブロックエディター用のパッケージ)
npm install @wordpress/scripts @wordpress/blocks @wordpress/i18n @wordpress/block-editor @wordpress/components @wordpress/data react react-dom
package.jsonにスクリプトが追記
{
"name": "my-theme-custom-block",
"version": "1.0.0",
"description": "My first WordPress custom block in a theme",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@wordpress/scripts": "^x.x.x"
}
}
@wordpress パッケージの型定義ファイルインストール
npm install --save-dev @types/wordpress__blocks
npm install --save-dev @types/wordpress__block-editor @types/wordpress__components
npm install @wordpress/data @wordpress/rich-text
npm install --save-dev @types/react @types/wordpress__rich-text
webpack
- ES6+やTypeScriptのコードを古いブラウザでも動作するES5に変換できます。
- モジュール間の依存関係を自動的に解析し、複数のJavaScriptファイルを1つのファイルにまとめます。
webpack.config.jsの設定
webpack.config.jsは、webpackの設定ファイルです。
webpack.config.js
const defaultConfig = require('@wordpress/scripts/config/webpack.config');
const path = require('path');
module.exports = {
...defaultConfig,
// エントリーポイントの設定
entry: {
lead: path.resolve(__dirname, 'wp-content/themes/originaltheme/src/lead/index.tsx'),
},
// 出力の設定
output: {
path: path.resolve(__dirname, 'wp-content/themes/originaltheme/build'),
filename: '[name].js', // [name] には entry で指定したキーが入る
},
// ファイルの拡張子を省略できるようにする
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
module: {
// ローダーの設定
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}
};
npm install ts-loader --save-dev
tsconfig.json
{
"compilerOptions": {
"target": "es5", // 出力するJavaScriptのバージョン
"module": "commonjs", // モジュールシステム
"strict": true, // 厳格な型チェックオプション
"esModuleInterop": true, // ESモジュールとの互換性
"skipLibCheck": true, // ライブラリの型チェックをスキップ
"forceConsistentCasingInFileNames": true, // ファイル名の大文字小文字の一貫性を強制
"jsx": "react", // JSXのサポート
"moduleResolution": "node", // モジュール解決方法
"resolveJsonModule": true, // JSONモジュールのインポートを許可
"outDir": "./build", // 出力ディレクトリ
"rootDir": "./wp-content/themes/originaltheme/src" // ソースファイルのルートディレクトリ
},
"include": [
"wp-content/themes/originaltheme/src/**/*" // コンパイル対象のファイル
],
"exclude": [
"node_modules" // コンパイル対象外のファイル
]
}
ブロックのソースファイルを作成
リッチテキストツールバーを使用
インライン単位で文字サイズ文字色を変更できるブロック
index.tsx
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import {
useBlockProps,
RichText,
RichTextToolbarButton,
} from '@wordpress/block-editor';
import {
registerFormatType,
applyFormat,
removeFormat,
type RichTextValue
} from '@wordpress/rich-text';
import React from 'react';
// ブロックの属性の型定義
interface BlockAttributes {
content: string;
}
// フォーマットの型定義
interface FormatProps {
isActive: boolean;
value: RichTextValue;
onChange: (value: RichTextValue) => void;
}
// WPFormat の型定義
interface WPFormatType {
name: string;
title: string;
tagName: string;
className: string;
interactive: boolean;
edit: (props: FormatProps) => JSX.Element;
}
// フォーマット名の定義
const FONT_SIZE_FORMAT = 'custom-format/font-size';
const TEXT_COLOR_FORMAT = 'custom-format/text-color';
// フォントサイズフォーマットの登録
const fontSizeFormat: WPFormatType = {
name: FONT_SIZE_FORMAT,
title: __('Font Size', 'custom-format'),
tagName: 'span',
className: 'custom-font-size',
interactive: false,
edit: ({ isActive, value, onChange }: FormatProps) => {
const fontSizes = ['0.75rem', '1rem', '2rem', '3rem', '4rem'];
// フォントサイズの変更の処理の関数
const onChangeFontSize = (size: string) => {
const newFormat = {
type: FONT_SIZE_FORMAT,
attributes: {
style: `font-size: ${size};`,
},
};
if (isActive) {
onChange(removeFormat(value, FONT_SIZE_FORMAT));
}
onChange(applyFormat(value, newFormat));
};
return (
<React.Fragment>
{fontSizes.map((size) => (
<RichTextToolbarButton
key={size}
icon="editor-textcolor"
title={`${size} ${__('Font Size', 'custom-format')}`}
onClick={() => onChangeFontSize(size)}
isActive={isActive}
/>
))}
</React.Fragment>
);
}
};
// 文字色フォーマットの登録
const textColorFormat: WPFormatType = {
name: TEXT_COLOR_FORMAT,
title: __('Red Text', 'custom-format'),
tagName: 'span',
className: 'custom-text-color',
interactive: false,
edit: ({ isActive, value, onChange }: FormatProps) => {
// 文字色の変更の処理の関数
const onToggleColor = () => {
if (isActive) {
onChange(removeFormat(value, TEXT_COLOR_FORMAT));
} else {
const newFormat = {
type: TEXT_COLOR_FORMAT,
attributes: {
style: 'color: red;',
},
};
onChange(applyFormat(value, newFormat));
}
};
return (
<RichTextToolbarButton
icon="editor-textcolor"
title={__('Red Text', 'custom-format')}
onClick={onToggleColor}
isActive={isActive}
/>
);
}
};
// フォーマットの登録
registerFormatType(FONT_SIZE_FORMAT, fontSizeFormat);
registerFormatType(TEXT_COLOR_FORMAT, textColorFormat);
// ブロックを登録
registerBlockType<BlockAttributes>('customtheme/cardlead', {
title: __('カード記事リード文', 'custom-block'),
icon: 'editor-textcolor',
category: 'text',
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'p',
},
},
edit: ({ attributes, setAttributes }) => {
const { content } = attributes;
const blockProps = useBlockProps({
className: 'my-custom-class',
style: {
borderTop: '8px solid #ffda00',
borderBottom: '8px solid #ffda00',
textAlign: 'center' as 'center',
}
});
return (
<div {...blockProps}>
<RichText
tagName="p"
value={content}
onChange={(newContent: string) => setAttributes({ content: newContent })}
placeholder={__('Select text and choose font size or color...', 'custom-block')}
allowedFormats={[
'core/bold',
'core/italic',
FONT_SIZE_FORMAT,
TEXT_COLOR_FORMAT
]}
/>
</div>
);
},
save: ({ attributes }) => {
const { content } = attributes;
const blockProps = useBlockProps.save({
className: 'my-custom-class',
style: {
borderTop: '8px solid #ffda00',
borderBottom: '8px solid #ffda00',
textAlign: 'center' as 'center',
}
});
return (
<div {...blockProps}>
<RichText.Content
tagName="p"
value={content}
/>
</div>
);
},
});
functions.phpで読み込み
functions.php
<?php
// カスタムブロックの登録
function my_theme_custom_block_init() {
// register_block_type()の第一引数は「ドメイン名/ブロック名」でregisterBlockType()の第一引数と一致させる
register_block_type( 'customtheme/cardlead', array(
'editor_script' => 'cardlead-script',
) );
}
add_action( 'init', 'my_theme_custom_block_init' );
// ブロックのスクリプトを読み込む
function my_theme_custom_block_enqueue_assets() {
$asset_file_cardlead = include( get_template_directory() . '/build/cardlead.asset.php' );
wp_enqueue_script(
'cardlead-script',
get_template_directory_uri() . '/build/cardlead.js',
$asset_file_cardlead['dependencies'],
$asset_file_cardlead['version']
);
}
add_action( 'enqueue_block_editor_assets', 'my_theme_custom_block_enqueue_assets' );