Open60

カスタムブロックつくる勉強

ちあきちあき
ちあきちあき

これはプラグインでやってるけど、テーマで書く場合は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( 'core/paragraph', {
    content: attributes.message,
} );

これは段落タグにTransformsブロックで入れた attributes.message をいれるってことか

ちあきちあき

type: 'block' はなんとなく使い方わかったような気がするけど、type: 'enter'ってなんだこれ……と思ったけど、このサンプルコードだったらrollout! って入力してenter押したらTransformsブロックに変わるぞってことか!使い所…… 🤔

ちあきちあき

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
);

こう。これだとリストブロックには適用されない 逆。リストだけ適用される

ちあきちあき
ちあきちあき
/**
 * 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パッケージからstoreblockEditorStoreとしてインポートしています。これは以下の利点を提供します:

  • 明示的な依存関係: 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)

ちあきちあき

なんか入れた文字数と合わないなーと思ったけど、これ英語の単語(半角スペース)でカウントされるのか!

ちあきちあき

わりと英語のドキュメントとかはGoogle翻訳でページごと変換して読んでるけど、理解しきれないなあと思ったら英文とコードまるごとコピってChatGPTにこれ解説して!って頼んだら割と読みやすく返してくれる。それはほんとうか……?って疑いの目は持つようにはしてるけども。

ちあきちあき
ちあきちあき
// 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の実装です。この関数は、複数の方法でエントリーポイントを検出し、それに基づいてオブジェクトを返します。主に、以下の三つの方法を使用しています:

  1. 環境変数経由で明示的に提供されたエントリーポイントの使用:

    • 環境変数WP_ENTRYが設定されている場合、その値(JSON形式と想定)をパースしてエントリーポイントのリストとして返します。これは主にレガシーシステムや特定のカスタマイズが必要な場合に使用されます。
  2. block.jsonファイルのスキャン:

    • 指定されたソースディレクトリ内のblock.jsonファイルを検出し、それらに定義されているスクリプトをエントリーポイントとして抽出します。block.jsonはWordPressブロックエディターでブロックのメタデータを定義するために使用されるファイルで、ブロックのスクリプトやスタイルなどが記述されています。この方法では、block.jsonファイル内でfile:プレフィックスを持つパスをエントリーポイントとして検出します。
  3. 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 を増やしたらビルドできた〜

ちあきちあき
ちあきちあき

このコードだとデフォルトでカバーブロックと画像ブロックがフェードインするかんじか。
フェードインするか否か選びたいときはスタイル追加かな

ちあきちあき
ちあきちあき

なぜかパネルのカスタムフィールドを表示してると更新できなくなる 🤔

ちあきちあき

updateMeta がカスタムフィールドの更新自体やってないのかなあ。
パネルを非表示にすると更新できるからバグ……?

ちあきちあき

ちゃんと値入ってるのかなーって確認したくて出しただけだから別に非表示でいいんだけどね 🤔

ちあきちあき
ちあきちあき

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">&lt;</button>
       <p>1/10</p>
       <button aria-label="go to next slide">&gt;</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">&lt;</button>
		<p>1/10</p>
		<button aria-label="go to next slide">&gt;</button>
	</div>
</div>
ちあきちあき
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したい

ちあきちあき

imageIndex で管理するなら

return `${ ctx.currentSlide + 1 }/${ ctx.totalSlides }`;

って書き方ができるからこっちのがよさそうだな