12
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Gutenberg】カスタムフィールド職人からカスタムブロック職人へ

Last updated at Posted at 2019-04-25

Gutenbergのカスタムブロックからpost metaを更新する方法や小ネタをまとめました。

PHPの部分は前記事にも記載してあるので参考にしてください。記事の途中にもコード例へのリンクを貼っています。
MVCモデル風WordPressカスタマイズ設計

カスタムブロック 開発環境

「Create Guten Block Toolkit」でサクッと開発環境を構築。

Create Guten Block Toolkit
https://ahmadawais.com/create-guten-block-toolkit/

下記の記事が導入の参考になりました。

Create Guten BlockでGutenbergのカスタムブロック開発環境を構築する
https://www.webopixel.net/wordpress/1420.html

src内は、1ブロック=1ディレクトリで作成する。
src内にブロック(ディレクトリ)を追加したら、src/blocks.jsに追加したjsファイルのimportを記述する。
エディタ内のブロックのスタイルは各ブロック(ディレクトリ)内のeditor.scssに記述する。
フロント表示時のスタイル用のblocks.style.build.cssを使わない場合は、src/init.phpの'enqueue_block_assets'のアクションフックを削除する(お好みで)。

ブロックカテゴリ・metaフィールドの準備

'block_categories'フィルターフックを使ってブロックカテゴリを追加。
投稿タイプによって、使用できるカスタムブロック(ブロックタイプ)を制限する場合は、'allowed_block_types'フィルターフックを使う。
register_meta()で事前に、metaフィールドを登録しておく。

コード例
init.php
setting.php
hooks/blocks.php

カスタムブロック の作成

各ブロック(ディレクトリ)内のblock.jsに記述する。

下記は、ブロックカテゴリ'block-post_type_1'にブロック'myplugin/image-section'を追加するコード例です。
色々試せるようにコンポーネントを多めに入れてみました。
setting.phpのブロックタイプ・metaフィールドとは部分的にしか対応してないので、コードを試す際には適宜補完してください。

block-image-section/block.js
import './editor.scss';

const {
  registerBlockType
} = wp.blocks;
const {
  RichText,
  MediaUpload
} = wp.editor;
const {
  PanelBody,
  BaseControl,
  TextControl,
  SelectControl,
  RadioControl,
  Button
} = wp.components;
const yearStart = 2019;
const yearEnd = 2030;
const linkType = [
  { label: '外部リンク', value: '' },
  { label: '内部リンク', value: '内部リンク' },
];

registerBlockType( 'myplugin/image-section', {
  title: '画像セクション登録',
  icon: 'edit',
  category: 'block-post_type_1',

  attributes: {
    title: {
      type: 'string',
      source: 'meta',
      meta: 'meta_title' // タイトル
    },
    content: {
      type: 'array',
      source: 'meta',
      meta: 'meta_content' // 説明文
    },
    year: {
      type: 'string',
      source: 'meta',
      meta: 'meta_year' // 撮影年
    },
    place: {
      type: 'string',
      source: 'meta',
      meta: 'meta_place' // 場所
    },
    url: {
      type: 'string',
      source: 'meta',
      meta: 'meta_link_url' // リンク先URL
    },
    type: {
      type: 'string',
      source: 'meta',
      meta: 'meta_link_type' // リンクタイプ
    },
    imageID: {
      type: 'number',
      source: 'meta',
      meta: 'meta_image_id' // 画像ID
    },
    imageURL: {
      type: 'string',
      source: 'meta',
      meta: 'meta_image_url' // 画像URL
    }
  },

  edit({attributes, setAttributes, className}) {
    function onSelectImage( media ) {
        setAttributes( {
            imageID: media.id,
            imageURL: media.url,
        } );
    }
    function onRemoveImage() {
        setAttributes( {
            imageID: null,
            imageURL: '',
        } );
    }
    function onChangeYear( event ) {
        setAttributes( { year: event.target.value } );
    }

    const optYear = [];
    for (let i = yearStart; i <= yearEnd; i++) {
      optYear.push(
        <option value={i} selected={i === Number(attributes.year)}>{i}</option>
      )
    }

    return (
      <PanelBody
        className={ className }
        title="画像セクション登録"
        icon="edit"
        initialOpen={ true }
      >
        <TextControl
          label="タイトル"
          help="画像タイトルを入力してください。"
          value={ attributes.title }
          onChange={ ( text ) => setAttributes( { title: text } ) }
        />
        <BaseControl
          label="説明文"
        >
          <RichText
            tagName="div"
            value={ attributes.content }
            onChange={ (content) => setAttributes( { content: content } ) }
          />
        </BaseControl>
        <SelectControl
            label="場所"
            help="撮影した場所を選択してください。"
            value={ attributes.place }
            options={ [
                { label: '選択なし', value: '' },
                { label: '屋内', value: '屋内' },
                { label: '屋外', value: '屋外' },
            ] }
            onChange={ ( option ) => { setAttributes( { place: option } ) } }
        />
        <BaseControl
          label="撮影年"
        >
          <select onChange={ onChangeYear } className="select-year">
            <option value='' selected={'' === attributes.year}>なし</option>
            {optYear}
          </select><p class="components-base-control__help">撮影した年を入力してください。</p>
        </BaseControl>
        <TextControl
          label="リンク先URL"
          value={ attributes.url }
          onChange={ ( text ) => setAttributes( { url: text } ) }
        />
        <RadioControl
          label="タイプを選択"
          selected={ attributes.type ? attributes.type : linkType[0].value }
          options={ linkType }
          onChange={ ( option ) => { setAttributes( { type: option } ) } }
        />
        <BaseControl
          label="画像登録"
        >
          <MediaUpload
              onSelect={ onSelectImage }
              type="image"
              value={ attributes.imageID }
              render={ ( { open } ) => (
                  <Button className={ attributes.imageID ? 'image-button' : 'button button-large' } onClick={ open }>
                      { ! attributes.imageID ? '画像アップロード': <img src={ attributes.imageURL } /> }
                  </Button>
              ) }
          />
          { ! attributes.imageID ? '': <Button className={ 'delete-image button button-large' } onClick={ onRemoveImage }>画像削除</Button> }
        </BaseControl>
      </PanelBody>
    );
  },

  save() {
    return null;
  },

} );
block-image-section/editor.scss
.wp-block-myplugin-image-section {
	.components-base-control .components-base-control__field {
		margin-bottom: 15px;

		.components-select-control__input {
			width: 200px;
		}
		.select-year {
			margin-right: 5px;
			margin-bottom: 15px;
		}
		.delete-image.button {
			margin-left: 1em;
			vertical-align: bottom;
		}
	}
	.components-base-control .components-base-control__label {
		margin: 5px 0;
		padding: .5em 10px .5em 10px;
		font-weight: bold;
		background-color: #f3f3f3;
	}
	.components-base-control .components-base-control__help {
		font-size: 12px;
	}
	.editor-rich-text {
		font-family: "Noto Serif", serif;
		font-size: 16px;
	}
}

投稿タイプにエディタのテンプレートを設定する

register_post_type()に'template'を設定することで、エディタのデフォルト表示にブロックが追加される。
後々のカスタムブロックの追加等の改修を想定して、'template_lock'は設定しない。
('template_lock'が設定してあると'template'を編集した際、既存の投稿が壊れる。)

コード例
hooks/post-type.php

フロントに表示する

get_registered_metadata()で投稿されたページのmetaデータを取得する。

コード例
controllers/single.php
single-post_type_1.php

12
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?