ブロックの設定を更新して各ブロックが編集メモ機能を所有するようにカスタマイズします。
コンテンツ
ブロックの雛形を生成する
npx @wordpress/create-block@latest editorial-notes --template @block-developer-cookbook/editorial-notes
ビルドプロセスを構成する
ブロックを作成しないため、@wordpress/scripts に使用するファイルの場所を定義する。
"start": "wp-scripts start src/notes-field.js",
"build": "wp-scripts build src/notes-field.js",
package.json
ファイル内の start
と build
コマンドを、src/notes.js
ファイルを指すように次のように更新する。
アセットをキューに追加する
editorial-notes.phpを編集して、notes-field.jsをエンキューする
/**
* Enqueue the JS containing our filters
*/
function editorial_notes_enqueue_scripts() {
$notes_field_file = plugin_dir_path( __FILE__ ) . '/build/notes-field.asset.php';
if ( file_exists( $notes_field_file ) ) {
$assets = include $notes_field_file;
// Enqueue the JavaScript that contains our filters.
wp_enqueue_script(
'notes-field',
plugin_dir_url( __FILE__ ) . '/build/notes-field.js',
$assets['dependencies'],
$assets['version'],
true
);
}
}
add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\editorial_notes_enqueue_scripts' );
editorial-notes.phpを編集して、notes-field.cssをエンキューする
/**
* Enqueue the editor only style
*/
function editorial_notes_enqueue_block_editor_css() {
$notes_field_file = plugin_dir_path( __FILE__ ) . '/build/notes-field.asset.php';
if ( file_exists( $notes_field_file ) ) {
$assets = include $notes_field_file;
// Enqueue the CSS for the has-notes class.
wp_enqueue_style(
'notes-class',
plugin_dir_url( __FILE__ ) . '/build/notes-field.css',
array(),
$assets['version'],
);
}
}
add_action( 'enqueue_block_assets', __NAMESPACE__ . '\editorial_notes_enqueue_block_editor_css' );
enqueue_block_editor_assetsとenqueue_block_assetsの違い
フック名 | 有効な場所 |
---|---|
enqueue_block_editor_assets | ブロックエディター内でのみ |
enqueue_block_assets | ブロックエディターとフロントエンドの両方 |
すべてのブロックにカスタム属性を追加する
エディターから追加されたメモを保持するために、各登録されたブロックにカスタムの「メモ」属性を追加する。これを行うために、blocks.registerBlockType
フィルターというブロックフィルターを使用する。このフィルターは、ブロックが登録される時点で、ブロックの設定を変更することができる。
このフィルターのコールバック関数は、パラメータとしてブロックの設定とブロック名を受け取る。
notes-field.jsにnotes属性を定義する
/**
* Filter the block settings to add the notes attribute.
*
* @param {Object} settings Settings for the block.
* @param {string} name The name of the block.
*
* @return {Object} he modified settings.
*/
function addNotesAttribute( settings, name ) {
return {
...settings,
attributes: {
...settings.attributes,
notes: {
type: 'string',
default: '',
},
},
};
addNotesAttribute
関数
ブロックの設定オブジェクトに新しい属性 notes
を追加する処理を行う
settings
: ブロックタイプの設定オブジェクト。ブロックに関する様々な設定が含まれており、attributes
プロパティもその一部。name
: この引数はブロックの名前
...settings
として元の設定をコピーした後、attributes
プロパティに新しい属性(notes
)を追加する
addFilter
の登録
addFilter(
'blocks.registerBlockType',
'block-developer-cookbook/notes-field',
addNotesAttribute
);
addFilter
関数
WordPress の フィルターフックを使って、特定のブロック登録処理にカスタム属性を追加している
'blocks.registerBlockType'
: Gutenberg ブロックタイプが登録される際に発火するフィルターフック。ブロックタイプの設定を変更することができる。'block-developer-cookbook/notes-field'
: フィルターの名前。addNotesAttribute
: 実際にブロックの設定に新しい属性を追加する関数
ノートを管理するためのコントロールを追加する
登録したカスタム属性を更新できるように、コントロールを作成する
/**
* Add a custom control to the block inspector controls for every block.
*
* @param {WPElement} BlockEdit The original block edit component.
*
* @return {WPElement} Element to render.
*/
function addEditorNotesField( BlockEdit ) {
return ( props ) => {
const {
attributes: { notes },
setAttributes
} = props;
return (
<>
<BlockEdit { ...props } />
<InspectorControls>
<PanelBody>
<TextareaControl
label={ __(
'Editorial Notes',
'block-developer-cookbook'
) }
value={ notes }
onChange={ ( notes ) =>
setAttributes( { notes } )
}
help={ __(
'Add some editorial notes for this block'
) }
/>
</PanelBody>
</InspectorControls>
</>
);
};
}
addEditorNotesField 関数
BlockEdit
コンポーネントを拡張する関数。BlockEdit
は Gutenberg ブロックの編集画面のコンポーネントで、ブロックの編集に関連する UI要素を追加する
- 関数内での処理
const {
attributes: { notes },
setAttributes,
isSelected,
} = props;
props
:BlockEdit
コンポーネントから渡されるプロパティattributes: { notes }
: このブロックの属性の中からnotes
を取り出すsetAttributes
:ブロックの属性を更新するための関数isSelected
: 現在このブロックが選択されているかどうかを示す Boolean 値
return (
<>
<BlockEdit { ...props } />
{ isSelected && (
<InspectorControls>
<PanelBody>
<TextareaControl
label={ __(
'Editorial Notes',
'block-developer-cookbook'
) }
value={ notes }
onChange={ ( newNotes ) =>
setAttributes( { notes: newNotes } )
}
help={ __(
'Add some editorial notes for this block'
) }
/>
</PanelBody>
</InspectorControls>
) }
</>
);
<BlockEdit { ...props } />
:BlockEdit
コンポーネントが元々持っているブロック編集UIがそのまま表示される。{ ...props }
で渡された全てのプロパティをそのままBlockEdit
に渡しているので、元のブロック編集機能を保持したまま新しい機能を追加している
addFilter
の登録
addFilter(
'editor.BlockEdit',
'block-developer-cookbook/notes-field-control',
addEditorNotesField
);
ブロックにメモがある場合に表示する
ブロックエディター内でブロックにメモがあることを表現する。
Gutenberg エディター内で表示されるブロックに対して、notes
属性の内容が存在する場合に has-notes
というクラスを付与する。
/**
* Add a custom class and CSS to show when a block has notes.
*
* @param {WPElement} BlockListBlock The original block list block component.
*
* @return {WPElement} Element to render.
*/
function addNotesDisplayClass( BlockListBlock ) {
return ( props ) => {
const { notes } = props.attributes;
return (
<BlockListBlock
{ ...props }
className={ notes.length ? 'has-notes' : '' }
/>
);
};
}
addFilter(
'editor.BlockListBlock',
'block-developer-cookbook/notes-field-class',
addNotesDisplayClass
);
addNotesDisplayClass
関数
addNotesDisplayClass
は、BlockListBlock
コンポーネントを拡張するための関数。BlockListBlock
は、Gutenberg エディター内で表示される各ブロックを表す
props
の取り扱い:
props
は、Gutenberg でブロックをレンダリングする際に渡されるプロパティのオブジェクト。このオブジェクトにはブロックに関する情報が含まれており、その中にattributes
というプロパティがあり、ブロックの設定(例えば、notes
属性など)が格納されている。notes
属性は、ブロック内に入力されたメモ(編集者メモ)
className
の設定:
className={ notes.length ? 'has-notes' : '' }
によって、notes
属性に内容があるブロックにはhas-notes
クラスが追加され、内容がない場合はクラスが追加されない
<BlockListBlock />
コンポーネントのレンダリング:
<BlockListBlock />
は、実際にブロックを表示するコンポーネント。{ ...props }
を使って、元々渡されているすべてのプロパティ(例えば、attributes
やsetAttributes
など)をそのまま渡している
コード全体
notes-field.js
/**
* WordPress dependencies
*/
import { addFilter } from '@wordpress/hooks';
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextareaControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import './notes.scss';
/**
* Filter the block settings to add the notes attribute.
*
* @param {Object} settings Settings for the block.
* @param {string} name The name of the block.
*
* @return {Object} he modified settings.
*/
function addNotesAttribute( settings, name ) {
return {
...settings,
attributes: {
...settings.attributes,
notes: {
type: 'string',
default: '',
},
},
};
}
addFilter(
'blocks.registerBlockType',
'block-developer-cookbook/notes-field',
addNotesAttribute
);
/*
* Add a custom control to the block inspector controls for every block.
*/
function addEditorNotesField( BlockEdit ) {
return ( props ) => {
const {
attributes: { notes },
setAttributes,
isSelected,
} = props;
return (
<>
<BlockEdit { ...props } />
{ isSelected && (
<InspectorControls>
<PanelBody>
<TextareaControl
label={ __(
'Editorial Notes',
'block-developer-cookbook'
) }
value={ notes }
onChange={ ( newNotes ) =>
setAttributes( { notes: newNotes } )
}
help={ __(
'Add some editorial notes for this block'
) }
/>
</PanelBody>
</InspectorControls>
) }
</>
);
};
}
addFilter(
'editor.BlockEdit',
'block-developer-cookbook/notes-field-control',
addEditorNotesField
);
/*
* Add a custom class and CSS to show when a block has notes.
*/
function addNotesDisplayClass( BlockListBlock ) {
return ( props ) => {
const { notes } = props.attributes;
return (
<BlockListBlock
{ ...props }
className={ notes.length ? 'has-notes' : '' }
/>
);
};
}
addFilter(
'editor.BlockListBlock',
'block-developer-cookbook/notes-field-class',
addNotesDisplayClass
);
editorial-notes.php
<?php
/**
* Plugin Name: Editorial Notes
* Description: Add editorial notes to each block that are stored in a custom attribute.
* Requires at least: 6.4
* Requires PHP: 7.0
* Version: 1.0.3
* Author: The WordPress Contributors
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: editorial-notes
*
* @package block-developers-cookbook
*/
namespace BlockDevelopersCookbook;
function editional_notes_enqueue_scripts() {
$note_field_file = plugin_dir_path(__FILE__) . '/build/notes-field.asset.php';
if (file_exists($note_field_file)) {
$assets = include $note_field_file;
wp_enqueue_script(
'notes-field',
plugin_dir_url(__FILE__) . '/build/notes-field.js',
$assets['dependencies'],
$assets['version'],
true
);
}
}
add_action('enqueue_block_editor_assets', __NAMESPACE__ . '\editional_notes_enqueue_scripts');
function editorial_notes_enqueue_block_editor_css() {
$note_field_file = plugin_dir_path(__FILE__) . '/build/notes-field.asset.php';
if (file_exists($note_field_file)) {
$assets = include $note_field_file;
wp_enqueue_style(
'note-class',
plugin_dir_url(__FILE__) . '/build/notes-field.css',
array(),
$assets['version'],
);
}
}
add_action('enqueue_block_assets', __NAMESPACE__ . '\editorial_notes_enqueue_block_editor_css');
package.json
{
"name": "editorial-notes",
"version": "1.0.3",
"description": "Add editorial notes to each block that are stored in a custom attribute.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build src/notes-field.js",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"start": "wp-scripts start src/notes-field.js"
},
"prettier": "@wordpress/prettier-config",
"devDependencies": {
"@wordpress/scripts": "^30.15.0"
}
}
notes.scss
.wp-block.has-notes::before {
content: '❗';
position: absolute;
z-index: 999;
top: -0.8rem;
left: -2rem;
height: 2rem;
font-size: 2rem;
}
.wp-block.has-notes {
border: 0.3rem dashed #ff0000;
}
参考:https://blockdevelopercookbook.com/recipes/editorial-notes/