Gutenbergで画像挿入が可能なオリジナルブロックの制作方法を紹介します。
1つの画像を挿入する方法から複数の画像、複数の画像を使用してギャラリーを制作する方法までを解説します。
ブロック制作の環境構築
この記事ではブロックを制作するための環境はそろっている前提で話を進めます。
オリジナルブロックの基本的な制作方法や環境構築については以下の記事を参考にしてください。
MediaUploadコンポーネント
画像を挿入するオリジナルブロックは@wordpress/block-editorが用意しているMediaUploadコンポーネントを使用することで制作する事が可能です。
edit.js
import {
  useBlockProps,
  MediaUpload,
  MediaUploadCheck
} from '@wordpress/block-editor';
import { Button } from '@wordpress/components';
export default function Edit({ attributes, setAttributes }) {
	const { mediaID, mediaURL } = attributes;
	const onImageSelected = ( media ) => {
		setAttributes( {
			mediaURL: media.url,
			mediaID: media.id,
		} );
	};
  const onMediaRemoved = () => {
		setAttributes({
			mediaID: 0,
			mediaURL: ''
		});
	};
  const blockProps = useBlockProps({
		className: 'c-image'
	});
   return (
    <div {...blockProps}>
      <MediaUploadCheck>
        <MediaUpload
          onSelect={ onImageSelected }
          allowedTypes={ ['image'] }
          value={ mediaID }
          render={ ( { open } ) => (
            <Button
              className = { mediaID ? 'image-button' : 'button button-large' }
              onClick = { open }>
              { ! mediaID ? "メディアライブラリを開く" : <img class="c-thumbnail__img" src={ mediaURL } alt="" loading="lazy" /> }
            </Button>
          ) }
        />
        { mediaID != 0 &&
          <MediaUploadCheck>
            <Button
              onClick = { onMediaRemoved }
              isLink
              isDestructive
              className="removeImage">画像を削除</Button>
          </MediaUploadCheck>
        }
      </MediaUploadCheck>
    </div>
  );
}
今回MediaUpload以外に使用するコンポーネントはMediaUploadCheckとButtonです。
MediaUploadCheckコンポーネントはログインしているユーザーが画像のアップ権限を持っているかどうかを確認する事ができるコンポーネントです。
MediaUploadCheckで全体を囲う事で画像を扱う権利が無い場合は画像を挿入できないようにします。(必要なければ外してください)
MediaUploadは画像一覧を開くコンポーネントですが、開くためのボタンは別で制作する必要がありますのでButtonコンポーネントを使用してボタンを制作します。
ボタンを自作したい場合はButtonコンポーネントではなく、htmlで制作しても問題ありません。
MediaUploadのプロパティの説明は以下になっています。
onSelect
メディアが選択されたとき呼び出されるコールバック関数をセットします。
このコールバック関数は選択したメディア(オブジェクト)が引数として渡されるので、そのオブジェクトからalt、url、idなど画像に関する情報を取得することができます。
allowedTypes
メディアライブラリからアップロードまたは選択するメディアの種類をセットします。
メディアライブラリという名前ですが、実はWordPressのメディアライブラリは画像以外にもpdfやExcelファイルなどもアップロードする事が可能です。
ですので、どの種類のデータを選択可能にするのかを指定します。
今回は画像全般という事でimageという文字列をセットします。
他にもさらに限定的にし、image/gifとする事でgif画像のみを選択可能にする事なども可能です。
メディアタイプについては以下を参考にしてセットしてください。
value
すでに選択されている画像がある場合に画像のIDをセットする事で画像を表示する事ができます。
保存した画像のIDはblock.jsonにセットしたmediaIDに保存しますのでattributesからmediaIDを取得し、valueにセットしています。
render
メディアライブラリを開くためのボタンをレンダリングするための関数をセットします。
mediaIDを確認し、mediaIDが存在すればボタンは表示せず、選択されている画像を表示、mediaIDが存在しなければ「メディアライブラリを開く」というボタンを表示しています。
44行目から52行目
画像の消去ボタンを制作しています。
mediaIDを確認し、mediaIDが存在すれば画像を消去するボタンを表示します。
onImageSelected関数
画像が選択された時に実行される関数です。
引数から選択した画像の情報を得る事ができます。
今回必要な情報は画像を表示するためのurlと画像を特定するためのidです。
altが必要な場合はaltも取得可能です。
取得した値はsetAttributesを使用して保存します。
onMediaRemoved関数
選択した画像を消す処理です。
setAttributesを使用してidとurlを空にします。
block.json
セットした値を保存するためにblock.jsonを修正します。
"attributes": {
	"mediaID": {
		"type": "number",
		"default": 0
	},
	"mediaURL": {
		"type": "string",
		"source": "attribute",
		"selector": "img",
		"attribute": "src"
	}
},
mediaURLはコメントデリミタではなく、htmlのsrc属性の値を使用しています。
コメントデリミタに関しては公式の属性ページとキーコンセプトページを参考にしてください。
save.js
今回最低限必要なものは画像のurlですのでmediaURLを取得し、imgタグにセットします。
import { useBlockProps } from '@wordpress/block-editor';
export default function save({ attributes }) {
	const { mediaURL } = attributes;
  return (
    <div { ...useBlockProps.save() } className="c-image">
      {
        mediaURL && (
          <img class="c-image__img-tag" src={ mediaURL } alt="" loading="lazy" />
        )
      }
    </div>
  );
};
複数選択可にする
複数の画像を選択できるようにするにはMediaUploadコンポーネントのmultipleをtrueにします。
edit.js
<MediaUpload
  multiple={ true } // trueにすると複数画像の選択が可能になる
  onSelect={ onImageSelected }
  allowedTypes={ ['image'] }
  value={ mediaID }
  render={ ( { open } ) => (
    <Button
      className = { mediaID ? 'image-button' : 'button button-large' }
      onClick = { open }>
      { ! mediaID ? "メディアライブラリを開く" : <img class="c-thumbnail__img" src={ mediaURL } alt="" loading="lazy" /> }
    </Button>
  ) }
/>
onImageSelectedの内容を変更する
複数枚の画像を保存出来るよう、関数を変更しましょう。
const onImageSelected = ( media ) => {
  const mediaID = media.map((image) => image.id);
  const mediaURL = media.map((image) => image.url);
  setAttributes( {
    mediaURL: mediaID,
    mediaID: mediaURL,
  } );
};
変更した値は配列で引数から受け取れます。
保存する形も配列ですので、mediaIDとmediaURLをそれぞれ配列に変換し、setAttributesを使用してそれぞれを保存します。
onMediaRemovedの内容を変更する
const onMediaRemoved = () => {
  setAttributes({
    mediaID: [],
    mediaURL: []
  });
};
renderの内容を変更する
複数の画像を表示できるようにループ処理で画像を出力します。
<MediaUpload
  multiple={ true } // trueにすると複数画像の選択が可能になる
  onSelect={ onImageSelected }
  allowedTypes={ ['image'] }
  value={ mediaID }
  render={ (( { open } ) => {
    if(mediaURL.length <= 0) {
      return (
        <Button
          className = { url ? 'image-button' : 'button button-large' }
          onClick = { open }>
            メディアライブラリを開く
        </Button>
      );
    };
    mediaURL.map((url, index) => {
      return (
        <Button
          className = { url ? 'image-button' : 'button button-large' }
          onClick = { open }>
          <img class="c-thumbnail__img" src={ url } alt="" loading="lazy" />
        </Button>
      )
    })
  })() }
/>
block.json
画像を1つ選択させる場合はmediaIDをのtypeをnumberとしていましたが、複数選択の場合は配列にする必用があります。
これはurlも同じです。
さらにurlはhtmlのsrcで値を保存していましたが、これも配列にしますのでコメントデリミタに変更します。
以下のようにblock.jsonを修正しましょう。
"attributes": {
	"mediaID": {
		"type": "array",
		"default": []
	},
	"mediaURL": {
		"type": "array",
		"default": []
	}
},
save.js
map関数でループさせすべての画像を表示します。
import { useBlockProps } from '@wordpress/block-editor';
export default function save({ attributes }) {
	const { mediaURL } = attributes;
  return (
    <div { ...useBlockProps.save() } className="c-image">
      {
        mediaURL.lenght <= 0 && (() => {
          mediaURL.map(url => {
            return (
              <img class="c-image__img-tag" src={ url } alt="" loading="lazy" />
            )
          })
        })
      }
    </div>
  );
};
ギャラリーモードにする
multipleをtrueにする事で複数選が可能になりますが、画像の並べ替えなどはできません。
並べ替えをするにはギャラリーモードにする必要があります。
ギャラリーモードにするためにはMediaUploadコンポーネントのgalleryをtrueにする必用があります。
<MediaUpload
  multiple={ true } // そのまま
  gallery={ true }  // 追加
  onSelect={ onImageSelected }
  allowedTypes={ ['image'] }
  value={ mediaID }
  render={ (( { open } ) => {略...})}
/>
		 
			