カスタムブロックつくる勉強
これを順番にやる
書いたコード置いとくリポジトリ作った
ブロックスタイルつけるためのコード。
これはプラグインでやってるけど、テーマで書く場合はfunctions.phpに register_block_style
書くよ
私はいつもこんな感じで書いてる
function custom_styles(): void {
/**
* Enqueue block styles.
*/
wp_enqueue_block_style(
'core/button',
array(
'handle' => 'custom-core-button',
'src' => get_parent_theme_file_uri( 'build/styles/blocks/core/button.css' ),
'path' => get_parent_theme_file_path( 'build/styles/blocks/core/button.css' ),
)
);
/**
* Register block styles.
*/
register_block_style(
'core/button',
array(
'name' => 'arrow-right',
'label' => '矢印つき',
'style_handle' => 'custom-core-button',
)
);
}
add_action( 'init', 'custom_styles' );
ブロックの変換のやつ。機能があるのは知ってたけど実際使ったことない(変換が必要になるカスタムブロックを作ったことないの意)
createBlock
ってなにしてるんかなーと調べるなどする
createBlock
Returns a block object given its type and attributes.
Parameters
- name string: Block name.
- attributes Object: Block attributes.
- innerBlocks ?Array: Nested blocks.
Returns
- Object: Block object.
つまり
createBlock( 'core/paragraph', {
content: attributes.message,
} );
これは段落タグにTransformsブロックで入れた attributes.message
をいれるってことか
type: 'block'
はなんとなく使い方わかったような気がするけど、type: 'enter'
ってなんだこれ……と思ったけど、このサンプルコードだったらrollout!
って入力してenter押したらTransformsブロックに変わるぞってことか!使い所…… 🤔
インナーブロックを持つブロック(グループなりカバーなり)の場合は、インナーブロックの中にブロック(段落とか)を createBlock
で作るという一工程追加作業が入る
Transform to
にカラムブロックとグループブロックがデフォルトで入ってるけど、これは置換ではなくラップ。
ブロックにメモ入れれるようにする方法。
Developer Resources見る感じ、適用するブロック絞りたい場合は
function addListBlockClassName( settings, name ) {
if ( name !== 'core/list' ) {
return settings;
}
return {
...settings,
supports: {
...settings.supports,
className: true,
},
};
}
wp.hooks.addFilter(
'blocks.registerBlockType',
'my-plugin/class-names/list-block',
addListBlockClassName
);
こう。これだとリストブロックには適用されない 逆。リストだけ適用される
SlotFill 🤔
/**
* WordPress dependencies
*/
import { registerPlugin } from '@wordpress/plugins';
import { PluginPostStatusInfo } from '@wordpress/edit-post';
import { useSelect } from '@wordpress/data';
const Render = () => {
// Get the blocks from the editor.
const blocks = useSelect(
( select ) => select( blockEditorStore ).getBlocks(),
[]
);
return (
<PluginPostStatusInfo>
{ `There are ${ blocks.length } blocks on the page` }
</PluginPostStatusInfo>
);
};
registerPlugin( 'block-developer-cookbook-word-counter', {
render: Render,
} );
これエラー出るよなーって思ってたけど、この時点だとstoreがimportされてないから blockEditorStore
?ハア?なにそれ?ってなってるわけね。だからここを select( 'core/block-editor' ).getBlocks()
にすれば動くと。
import { store as blockEditorStore } from '@wordpress/block-editor';
でblockEditorStore
を参照する方法と、直接select('core/block-editor').getBlocks()
を使用する方法の主な違いは、依存性の明示と将来の変更への対応力にあります。機能的には同じ結果を得ることができますが、それぞれのアプローチには以下のような特徴があります。
blockEditorStore
を使う方法
import { store as blockEditorStore } from '@wordpress/block-editor';
const blocks = useSelect(
( select ) => select( blockEditorStore ).getBlocks(),
[]
);
この方法では、@wordpress/block-editor
パッケージからstore
をblockEditorStore
としてインポートしています。これは以下の利点を提供します:
-
明示的な依存関係:
blockEditorStore
を直接インポートすることで、依存しているストアがコード上で明示的に示されます。これにより、コードの可読性が向上し、他の開発者がコードを理解しやすくなります。 -
リファクタリングと保守の容易さ: もし将来
@wordpress/block-editor
のストアの名前が変更された場合、その変更をimport
文で一箇所だけ更新すれば良くなります。直接文字列でストア名を記述する方法では、ストア名が使用されているすべての場所を探して更新する必要があります。 - 自動補完と型チェックのサポート: 静的型付けをサポートする環境(TypeScriptなど)や、IDEの自動補完機能を使用している場合、インポートしたストアを使うことで、利用可能なメソッドやセレクターに関する情報を簡単に取得できます。
select('core/block-editor').getBlocks()
を使う方法
const blocks = useSelect(
( select ) => select('core/block-editor').getBlocks(),
[]
);
この方法では、ストアの名前(この場合は'core/block-editor'
)を直接文字列としてselect
関数に渡しています。このアプローチの特徴は以下の通りです:
- 簡潔さ: インポートを行う必要がないため、コードが少し短くなります。
- 柔軟性: ストアの名前を動的に指定したい場合(例えば、複数の異なるストアからデータを取得する共通関数を作成する場合など)に便利です。
結論
両方法は機能的には同じ結果をもたらしますが、blockEditorStore
をインポートして使用する方法は、将来的な変更への対応、コードの明示性、そして開発者ツールのサポートの面で優れています。そのため、特に大規模なプロジェクトやチームでの開発では、この方法が推奨されます。
だそうです。(ChatGPT)
なんか入れた文字数と合わないなーと思ったけど、これ英語の単語(半角スペース)でカウントされるのか!
日本語をカウントしたいときは、WPWordCountStrategy
を characters_excluding_spaces
にする
const { lockPostSaving, unlockPostSaving } = useDispatch( editorStore );
editorStore は @wordpress/editor
からインポートしてる。設定できる値は以下参照
わりと英語のドキュメントとかはGoogle翻訳でページごと変換して読んでるけど、理解しきれないなあと思ったら英文とコードまるごとコピってChatGPTにこれ解説して!って頼んだら割と読みやすく返してくれる。それはほんとうか……?って疑いの目は持つようにはしてるけども。
@wordpress/xxx
のリファレンスこれか
// Import the original config from the @wordpress/scripts package.
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
// Import the helper to find and generate the entry points in the src directory
const { getWebpackEntryPoints } = require( '@wordpress/scripts/utils/config' );
// Export the webpack config.
module.exports = {
...defaultConfig,
entry: {
...getWebpackEntryPoints(),
variations: './resources/js/variations.js',
'variation-styles': './resources/scss/variation.scss',
},
};
これもしかして getWebpackEntryPoints
使ったらブロックのentry足さなくていい?
デフォルトブロックのスタイル追加したりするときはいつもこういう書き方をしてる
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const RemoveEmptyScriptsPlugin = require( 'webpack-remove-empty-scripts' );
const path = require( 'path' );
const glob = require( 'glob' );
const blockStyleDir = 'src/styles';
const blockEntries = glob
.sync( 'blocks/**/*.css', {
cwd: blockStyleDir,
} )
.map( ( key ) => [
`styles/${ key.replace( '.css', '' ) }`,
path.resolve( process.cwd(), blockStyleDir, key ),
] );
const blockEntriesObj = Object.fromEntries( blockEntries );
module.exports = {
...defaultConfig,
entry: {
...defaultConfig.entry,
'styles/theme/theme': path.resolve(
process.cwd(),
'src/styles/theme/theme.css'
),
'scripts/theme': path.resolve( process.cwd(), 'src/scripts/theme.js' ),
...blockEntriesObj,
}
...
};
うーん、そんなうまい話でもなさそうだな
なかみ
このコードは、Webpackのエントリーポイントを動的に検出して生成するための関数getWebpackEntryPoints
の実装です。この関数は、複数の方法でエントリーポイントを検出し、それに基づいてオブジェクトを返します。主に、以下の三つの方法を使用しています:
-
環境変数経由で明示的に提供されたエントリーポイントの使用:
- 環境変数
WP_ENTRY
が設定されている場合、その値(JSON形式と想定)をパースしてエントリーポイントのリストとして返します。これは主にレガシーシステムや特定のカスタマイズが必要な場合に使用されます。
- 環境変数
-
block.json
ファイルのスキャン:- 指定されたソースディレクトリ内の
block.json
ファイルを検出し、それらに定義されているスクリプトをエントリーポイントとして抽出します。block.json
はWordPressブロックエディターでブロックのメタデータを定義するために使用されるファイルで、ブロックのスクリプトやスタイルなどが記述されています。この方法では、block.json
ファイル内でfile:
プレフィックスを持つパスをエントリーポイントとして検出します。
- 指定されたソースディレクトリ内の
-
src/index.*
ファイルのフォールバック:- ソースディレクトリ内に
index.js
またはindex.ts
(拡張子が.jsx
や.tsx
の場合も含む)ファイルが存在する場合、そのファイルをエントリーポイントとして使用します。これは、上記の方法でエントリーポイントが検出されなかった場合のフォールバックとして機能します。
- ソースディレクトリ内に
関数内のロジックは以下のように構成されています:
- まず、環境変数
WP_ENTRY
が設定されているかをチェックし、設定されていればその値を使用します。 - 次に、ソースディレクトリが存在するかを確認し、存在する場合は
block.json
ファイルをスキャンしてエントリーポイントを検出します。 -
block.json
ファイルからエントリーポイントを抽出する際には、ファイルが正しいJSON形式であるか、そして指定されたパスがソースディレクトリ内に存在するかを確認します。 - 最後に、上記の方法でエントリーポイントが検出されなかった場合には、
src/index.*
ファイルをエントリーポイントとして使用します。
この関数は、特にWordPress環境でのブロック開発やテーマ開発において、エントリーポイントの管理を簡素化し、自動化するために便利です。それにより、開発者はエントリーポイントを手動で管理する手間を省くことができます。
from ChatGPT
私の理解が間違ってなければこれはカスタムブロック向きのエントリーポイントの書き方っぽい?
wp_enqueue_block_style
とかでスタイル上書きさせるときには使えそうにないなあ。残念。
blocks
ディレクトリの中で custom-block-2
を増やしたらビルドできた〜
おお…
ついにきた
data-wp-interactive='{ "namespace": "gallery-slider" }'
ここに設定するnamespace
は、view.jsのstore
で定義したやつと同じにする。block.json の name
じゃないので注意
<?php
$context = array_merge(
$attributes,
array(
'slides' => array(),
'currentSlide' => 0,
'totalSlides' => 0,
)
);
?>
<div <?php echo wp_kses_data( get_block_wrapper_attributes() ); ?>
data-wp-interactive='{ "namespace": "gellery-slider" }'
<?php echo data_wp_context( $context ); ?>
>
<div class="slider-container">
<?php echo wp_kses_post( $content ); ?>
</div>
<div class="buttons">
<button aria-label="go to previous slide"><</button>
<p>1/10</p>
<button aria-label="go to next slide">></button>
</div>
</div>
って紹介されてるけど、なんかエラーがでる。ここは wp_interactivity_data_wp_context
が正解っぽい。
<?php
$context = array_merge(
$attributes,
array(
'slides' => array(),
'currentSlide' => 0,
'totalSlides' => 0,
)
);
?>
<div <?php echo wp_kses_data( get_block_wrapper_attributes() ); ?>
data-wp-interactive='{ "namespace": "gallery-slider" }'
<?php echo wp_interactivity_data_wp_context( $context ); ?>
>
<div class="slider-container">
<?php echo wp_kses_post( $content ); ?>
</div>
<div class="buttons">
<button aria-label="go to previous slide"><</button>
<p>1/10</p>
<button aria-label="go to next slide">></button>
</div>
</div>
ふつーーーにStep 5動かんくてワロタ。
const { state, actions, callbacks } = store( "gallery-slider", {
state: {},
actions: {
prevSlide: () => {
console.log( 'Previous image' );
},
nextSlide: () => {
console.log( 'Next image' );
},
},
callbacks: {},
} );
で試しても駄目
ぼけくそかす!build
には--experimental-modules
いれてたけどなぜかstart
に入れ忘れてた!
view.jsがビルドされてないなということに旦那氏が気づいてpackage.json 見直したら入ってなかったよね
<span data-wp-text="context.currentSlide"></span>
これで今のスライドの場所、<span data-wp-text="context.totalSlides"></span>
でトータルの数が表示できる。でもこれ0始まりの値だから、1始まり+トータルカウントから-1したい
ここの実装参考にするに、state
で管理してる。確かにスライドの番号変わるからこの形式で持っておくのはアリか
imageIndex
で管理するなら
return `${ ctx.currentSlide + 1 }/${ ctx.totalSlides }`;
って書き方ができるからこっちのがよさそうだな
onKeyDown
でスライド移動すると2つ単位で動くのなんでかな〜って思ってたけど、data-wp-on-document--keydown
は親につけないと駄目なやつだった。ちゃんとドキュメント見ましょうねだし、ご丁寧にdocument
って書いてる時点で察しろという話