Edit
edit
関数は、エディタのコンテキストにおけるブロックの構造を説明します。これは、ブロックが使用されるときにエディタがレンダリングするものを表します。
import { useBlockProps } from '@wordpress/block-editor';
// ...
const blockSettings = {
apiVersion: 3,
// ...
edit: () => {
const blockProps = useBlockProps();
return <div { ...blockProps }>Your block.</div>;
},
};
Block wrapper props
ここで最初に注目すべきは、ブロックラッパー要素に useBlockProps
React フックを使用していることです。上記の例では、ブロックラッパーはエディタ内で「div」をレンダリングしますが、Gutenberg エディタがブロックを操作する方法を知るためには、ブロックに必要な追加の classNames を追加する必要があります… ブロックラッパー要素は useBlockProps
React フック呼び出しから取得した props を適用する必要があります。ブロックラッパー要素は、<div>
や <table>
のようなネイティブ DOM 要素、または追加の props をネイティブ DOM 要素に転送する React コンポーネントであるべきです。例えば、<Fragment>
や <ServerSideRender>
コンポーネントを使用することは無効です。
要素ラッパーに追加のカスタム HTML 属性が必要な場合、これらは useBlockProps
フックへの引数として渡す必要があります。例えば、ラッパーに my-random-classname
className を追加するには、次のコードを使用できます:
import { useBlockProps } from '@wordpress/block-editor';
// ...
const blockSettings = {
apiVersion: 3,
// ...
edit: () => {
const blockProps = useBlockProps( {
className: 'my-random-classname',
} );
return <div { ...blockProps }>Your block.</div>;
},
};
attributes
edit
関数は、オブジェクト引数を通じていくつかのプロパティも受け取ります。これらのプロパティを使用して、ブロックの動作を適応させることができます。
attributes
プロパティは、ブロックタイプが登録されたときに attributes
プロパティによって説明されるすべての利用可能な属性とその対応する値を表面化します。属性ソースを指定する方法については、attributes documentation を参照してください。
この場合、ブロック登録中に content
の属性を定義したと仮定すると、その値を編集関数内で受け取り、使用します:
edit: ( { attributes } ) => {
const blockProps = useBlockProps();
return <div { ...blockProps }>{ attributes.content }</div>;
};
attributes.content
の値は、エディタ内でブロックを挿入する際に div
内に表示されます。
isSelected
isSelected プロパティは、ブロックが現在選択されているかどうかを示すブール値です。
edit: ( { attributes, isSelected } ) => {
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
Your block.
{ isSelected && (
<span>Shows only when the block is selected.</span>
) }
</div>
);
};
setAttributes
この関数は、ユーザーの操作に基づいてブロックが個々の属性を更新できるようにします。
edit: ( { attributes, setAttributes, isSelected } ) => {
const blockProps = useBlockProps();
// Simplify access to attributes
const { content, mySetting } = attributes;
// Toggle a setting when the user clicks the button
const toggleSetting = () => setAttributes( { mySetting: ! mySetting } );
return (
<div { ...blockProps }>
{ content }
{ isSelected && (
<button onClick={ toggleSetting }>Toggle setting</button>
) }
</div>
);
};
オブジェクトや配列である属性を使用する場合、更新する前に属性をコピーまたはクローンすることをお勧めします:
// Good - a new array is created from the old list attribute and a new list item:
const { list } = attributes;
const addListItem = ( newListItem ) =>
setAttributes( { list: [ ...list, newListItem ] } );
// Bad - the list from the existing attribute is modified directly to add the new list item:
const { list } = attributes;
const addListItem = ( newListItem ) => {
list.push( newListItem );
setAttributes( { list } );
};
なぜこれをするのか? JavaScript では、配列とオブジェクトは参照によって渡されるため、この慣行は、変更が同じデータへの参照を保持している他のコードに影響を与えないことを保証します。さらに、Gutenberg プロジェクトは、状態は不変であるべきという Redux ライブラリの哲学に従っています—データは直接変更されるべきではなく、代わりに変更を含む新しいバージョンのデータが作成されるべきです。
Save
save
関数は、異なる属性を最終的なマークアップにどのように組み合わせるかを定義し、その後 post_content
にシリアライズされます。
save: () => {
const blockProps = useBlockProps.save();
return <div { ...blockProps }> Your block. </div>;
};
ほとんどのブロックでは、save
の戻り値は、サイトのフロントでブロックがどのように表示されるかを表す WordPress Element のインスタンス であるべきです。
注意: save
から文字列値を返すことは可能ですが、エスケープされます。文字列に HTML マークアップが含まれている場合、マークアップはサイトのフロントにそのまま表示され、同等の HTML ノードコンテンツとして表示されることはありません。save
から生の HTML を返す必要がある場合は、wp.element.RawHTML
を使用してください。名前が示すように、これは クロスサイトスクリプティング に対して脆弱であるため、可能な限り WordPress Element 階層を使用することが推奨されます。
注意: save 関数は、呼び出すために使用される属性のみに依存する純粋な関数であるべきです。
他のソースから情報を取得したり、副作用を持つことはできません。例えば、select( store ).selector( ... )
内でデータモジュールを使用することはできません。
これは、外部情報が変更された場合、投稿が後で編集されるときにブロックが無効としてフラグ付けされる可能性があるためです(Validation についてもっと読む)。
保存の一部として他の情報が必要な場合、開発者は次の2つの代替案のいずれかを検討できます:
- 動的ブロック を使用し、サーバー上で必要な情報を動的に取得します。
- 外部値を属性として保存し、変更が発生するたびにブロックの
edit
関数で動的に更新します。
動的ブロック の場合、save
の戻り値は、プラグインが無効になった場合にのみ表示されるブロックのコンテンツのキャッシュコピーを表すことができます。
指定されていない場合、デフォルトの実装は動的ブロックの投稿コンテンツにマークアップを保存せず、代わりにブロックがサイトのフロントに表示されるときに常に計算されるようにします。
block wrapper props
edit
関数と同様に、静的ブロックをレンダリングする際には、useBlockProps.save()
によって返されるブロックプロパティをブロックのラッパー要素に追加することが重要です。これにより、ブロッククラス名が正しくレンダリングされ、ブロックサポート API によって注入された HTML 属性も正しくレンダリングされます。
attributes
edit
と同様に、save
関数もマークアップに挿入できる属性を含むオブジェクト引数を受け取ります。
save: ( { attributes } ) => {
const blockProps = useBlockProps.save();
return <div { ...blockProps }>{ attributes.content }</div>;
};
ブロックを保存する際には、属性ソース定義で指定されたのと同じ形式で属性を保存したいと考えています。属性ソースが指定されていない場合、属性はブロックのコメント区切りに保存されます。詳細については、Block Attributes documentation を参照してください。
Examples
ここでは、属性、編集、保存をすべて一緒に使用するいくつかの例を示します。
Saving Attributes to Child Elements
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'div'
}
},
edit: ( { attributes, setAttributes } ) => {
const blockProps = useBlockProps();
const updateFieldValue = ( val ) => {
setAttributes( { content: val } );
}
return (
<div { ...blockProps }>
<TextControl
label='My Text Field'
value={ attributes.content }
onChange={ updateFieldValue }
/>
</div>
);
},
save: ( { attributes } ) => {
const blockProps = useBlockProps.save();
return <div { ...blockProps }> { attributes.content } </div>;
},
Saving Attributes via Serialization
理想的には、保存された属性はマークアップに含まれるべきです。しかし、これは実用的でない場合があるため、属性ソースが指定されていない場合、属性はシリアライズされ、ブロックのコメント区切りに保存されます。
この例は、サーバーサイドでマークアップをレンダリングする Latest Posts block のような動的ブロックに該当する可能性があります。保存関数は依然として必要ですが、この場合、ブロックがエディタからコンテンツを保存していないため、単に null を返します。
attributes: {
postsToShow: {
type: 'number',
}
},
edit: ( { attributes, setAttributes } ) => {
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<TextControl
label='Number Posts to Show'
value={ attributes.postsToShow }
onChange={ ( val ) => {
setAttributes( { postsToShow: parseInt( val ) } );
}}
/>
</div>
);
},
save: () => {
return null;
}
Validation
エディタが読み込まれると、投稿コンテンツ内のすべてのブロックが検証され、その正確性が判断され、コンテンツの損失を防ぎます。これは、ユーザーがエディタがブロックを正しく復元できない場合、意図せずにコンテンツを削除または変更する可能性があるため、ブロックの保存実装に密接に関連しています。エディタの初期化中に、各ブロックの保存されたマークアップは、投稿のコンテンツから解析された属性を使用して再生成されます。新しく生成されたマークアップが投稿コンテンツに既に保存されているものと一致しない場合、ブロックは無効としてマークされます。これは、ユーザーが編集を行わない限り、マークアップは保存されたコンテンツと同一であるべきだと仮定するためです。
ブロックが無効であると検出された場合、ユーザーは無効化を処理する方法を選択するように促されます:
Attempt Block Recovery ボタンをクリックすると、可能な限り回復アクションが試みられます。
ブロックの横にある「3-dot」メニューをクリックすると、3つのオプションが表示されます:
- Resolve: 2つのボタンを持つ Resolve Block ダイアログボックスを開きます:
- Convert to HTML: 保存された投稿コンテンツから元のマークアップを保護し、ブロックを元のタイプから HTML ブロックタイプに変換し、ユーザーが HTML マークアップを直接変更できるようにします。
- Convert to Blocks: 保存された投稿コンテンツから元のマークアップを保護し、ブロックを元のタイプから検証されたブロックタイプに変換します。
- Convert to HTML: 保存された投稿コンテンツから元のマークアップを保護し、ブロックを元のタイプから HTML ブロックタイプに変換し、ユーザーが HTML マークアップを直接変更できるようにします。
- Convert to Classic Block: 保存された投稿コンテンツから元のマークアップを正しいものとして保護します。ブロックは元のタイプから Classic ブロックタイプに変換されるため、元のブロックタイプのコントロールを使用してコンテンツを編集することはできなくなります。
Validation FAQ
ブロックが無効になるのはどうしてですか?
ブロックの無効化の最も一般的な2つの原因は:
- 1. ブロックのコードに欠陥があると、意図しないコンテンツの変更が発生します。プラグイン作成者としてブロックの無効化をデバッグする方法については、以下の質問を参照してください。
- 2. あなたまたは外部エディタがブロックの HTML マークアップを変更し、それがもはや正しいと見なされなくなった。
私はプラグイン作成者です。ブロックが無効としてマークされる理由をデバッグするにはどうすればよいですか?
デバッグを開始する前に、ブロックが無効であるかどうかを検出するプロセスを文書化した上記の検証ステップに慣れておくことをお勧めします。ブロックが無効であるのは、再生成されたマークアップが投稿コンテンツに保存されているものと一致しない場合であるため、これはしばしばブロックの属性が保存されたコンテンツから正しく解析されていないことが原因です。
attribute sources を使用している場合、マークアップから取得された属性が期待通りに正確に保存され、正しいタイプ(通常は 'string'
または 'number'
)であることを確認してください。
ブロックが無効として検出されると、警告がブラウザの開発者ツールコンソールに記録されます。警告には、マークアップの違いが発生した正確なポイントに関する具体的な詳細が含まれます。期待されるマークアップと実際のマークアップの違いを注意深く確認し、問題が発生している場所を特定してください。
ブロックの save
動作を変更したため、古いコンテンツに無効なブロックが含まれています。これを修正するにはどうすればよいですか?
意図的なマークアップの変更におけるレガシーコンテンツに対応する方法については、Deprecated Blocks のガイドを参照してください。