Gutenberg(ブロックエディタ)メモ: Toggleを使う

WordPressのGutenberg
WordPressのGutenberg

WordPressのGutenbergハンドブックに載っている記述そのままでは作る方法が分からず、別の方法での実装を試した内容です。

構築環境
WordPress4.9.8
JavaScriptJSX/ESNext
Gutenberg4.0

注意点

  • Gutenbergがコアに入る前の段階の記事です
  • 書き方だけではなく、語句や名称にも問題がある可能性があります
  • バッドノウハウな状態だと思いますので、読む方は参考程度に考えてください
  • 私自身の書き方がまだ固まっていないためと参考にしたサンプルの都合上、当ブログ内のサンプルコードにはアロー関数の使用の有無などに表記揺れがあります

実現したいこと

  • Gutenbergでブロック編集時にトグルボタンを付ける
  • トグルをテキストエディタの上部に表示させる

トグルはサイドでも良かったのですが、簡単に位置が移動できるので、試しにエディタの上に入れたサンプルを目指しました。

ハンドブックでは以下のページに説明があります。

サンプル

ToggleControl完成例
ToggleControl

今回重要なのは、ハンドブックにあるwithStateを使っていない点です。
ハンドブックの書き方や仕組みを再現したわけではない点に留意してください。

以下は「テキストエディタの入力欄上部にトグルボタンを付ける」という動作を目的としたサンプルです。
あまり実用性はありませんが、一応記事出力時にはトグルによって内容が変わる文章も出力します。


//初期設定
add_action( 'enqueue_block_editor_assets', function() {
  wp_enqueue_script(
    'myplugin-gutenberge',
    plugins_url( 'block.js', __FILE__ ),
    [ 'wp-blocks', 'wp-element', 'wp-components', 'wp-editor' ]
  );
} );

const { registerBlockType } = wp.blocks;
const { Fragment } = wp.element;
const {
    RichText,
    BlockControls,
    AlignmentToolbar
} = wp.editor;
const { ToggleControl } = wp.components;
const testImgSetTextareaStyle = { border: '1px solid #ccc' };

registerBlockType( 'my-plugin/test-inspector-toggle', {
  title: 'test-inspector-toggle',
  icon: 'universal-access-alt',
  category: 'layout',

  attributes: {
    content: {
      type: 'array',
      source: 'children',
      selector: 'p',
    },
    alignment: {
      type: 'string',
    },
    toggle: {
      type: 'boolean',
      default: false,
    }
  },
  edit({ attributes, setAttributes } ) {
    const { content, alignment, toggle } = attributes;

    const onChangeContent = newContent => {
      setAttributes( { content: newContent } );
    };
    const onChangeAlignment = newAlignment => {
      setAttributes( { alignment: newAlignment } );
    }
    const onChangeToggle = newToggle => {
      setAttributes( { toggle: newToggle } );
    }

    return(
      <Fragment>
        <BlockControls>
          <AlignmentToolbar
            value={ alignment }
            onChange={ onChangeAlignment }
          />
        </BlockControls>
        <ToggleControl
          label="推敲した?"
          help={ toggle ? 'OK!' : 'NO!' }
          checked={ toggle }
          onChange={ onChangeToggle }
        />
        <hr />
        <RichText
          key="editable"
          tagName="p"
          style={ { textAlign: alignment } , testImgSetTextareaStyle }
          onChange={ onChangeContent }
          value={ content }
        />
        <p className={ toggle ? 'toggle-on' : false }>
          { toggle ? 'toggle ON' : 'toggle OFF' }
        </p>
      </Fragment>
    );
  },
  save( { attributes, className } ) {
    const { content, alignment, toggle } = attributes;
    return (
      <div className={ className }>
        <RichText.Content
          style={ { textAlign: alignment } }
          value={ content }
          tagName="p"
        />
        <p class="note">この文章は{ attributes.toggle ? '推敲済みです。' : '推敲されていません。' }</p>
        <p className={ toggle ? 'toggle-on' : false }>
          { toggle ? 'toggle ON' : 'toggle OFF' }
        </p>
      </div>
    );
  },
} );

ハンドブックではwithStateを使っていますが、この形で値を取り出す公式的な方法がわからず、主に下記ページを参考にしながらかなり無理矢理に作った状態です。

説明入りサンプル


//ブロックが作れるようにregisterBlockTypeを読み込む
const { registerBlockType } = wp.blocks;
//editやsave内で<Fragment>が使えるように、 wp.elementから読み込む
const { Fragment } = wp.element;
//editやsave内で<RichText>などが使えるように、 wp.editorから読み込む
const {
    RichText,
    BlockControls,
    AlignmentToolbar
} = wp.editor;
//editやsave内で<ToggleControl>が使えるように、 wp.componentsから読み込む
const { ToggleControl } = wp.components;
//装飾用の設定
const testImgSetTextareaStyle = { border: '1px solid #ccc' };

//編集画面用の設定を作成
registerBlockType( 'my-plugin/test-toggle', {
  //iconやcategoryなどの設定(Title以外は参考にしたコードのまま決定)
  title: 'test-toggle',
  icon: 'universal-access-alt',
  category: 'layout',

  //属性とその値を利用できるように設定。初期設定のようなもの。
  //atributesに入れてしまえば、edit内の値をsave内に簡単に持ち込める
  attributes: {
    content: {
      type: 'array',
      source: 'children',
      selector: 'p',
    },
    alignment: {
      type: 'string',
    },
    toggle: {
      type: 'boolean',
      //toggleの初期値を設定
      default: false,
    }
  },

  //editは投稿画面内の内容を設定
  edit({ attributes, setAttributes } ) {
    //attributesでまとめていた各属性を分けて使えるようにする
    //こうしておけば{toggle}と書けばtoggle: falseのように出力される
    const { content, alignment, toggle } = attributes;

    //RichTextへの入力内容を取得して更新する
    const onChangeContent = newContent => {
      setAttributes( { content: newContent } );
    };
    //AlignmentToolbarの値を取得して更新する
    const onChangeContent = newAlignment => {
      setAttributes( { alignment: newAlignment } );
    }
    //選択されたトグルの真偽値をattributes内のtoggleに設定
    const onChangeToggle = newToggle => {
      setAttributes( { toggle: newToggle } );
    }

    return(
      <Fragment>
        {//ブロックの上の場所を指定
        }
        <BlockControls>
          <AlignmentToolbar
            value={ alignment }
            onChange={ onChangeAlignment }
          />
        </BlockControls>
        <ToggleControl
          label="推敲した?"
          {//トグルの真偽値で内容が変わる。不要ならこの部分は消してOK
          }
          help={ toggle ? 'OK!' : 'NO!' }
          checked={ toggle }
          onChange={ onChangeToggle } 
        />
        <hr />
        {//リッチテキストエディタの設定
        }
        <RichText
          key="editable"
          tagName="p"
          style={ { textAlign: alignment } , testImgSetTextareaStyle }
          onChange={ onChangeContent }
          value={ content }
        />
        {//toggleの値でclassを出力を操作。falseを設定した場合、その項目自体が無効化されるためclass自体が出力されない
        }
        <p className={ toggle ? 'toggle-on' : false }>
          { toggle ? 'toggle ON' : 'toggle OFF' }
        </p>
      </Fragment>
    );
  }),
  //saveは保存時の内容を設定。基本的にはそのまま出力されるので、記事表示時の内容とほぼ同義。
  //最初に設定し、edit内で操作したattributesの値をattributesと書くことでまとめて引数にしている
  save( { attributes, className } ) {
    //attributesでまとめていた各属性を分けて使えるようにする
    const { content, alignment, toggle } = attributes;
    return (
      <div className={ className }>
        <RichText.Content
          style={ { textAlign: alignment } }
          value={ content }
          tagName="p"
        />
        {//トグルの真偽値によって文章を分岐させる
        }
        <p class="note">この文章は{ attributes.toggle ? '推敲済みです。' : '推敲されていません。' }</p>
        {//toggleの値でclassを出力を操作。falseを設定した場合、その項目自体が無効化されるためclass自体が出力されない
        }
        <p className={ toggle ? 'toggle-on' : false }>
          { toggle ? 'toggle ON' : 'toggle OFF' }
        </p>
      </div>
    );
  },
} );

Toggleでclassを変更する

前項の以下の部分でclassを変更が可能です。


{//toggleの値でclassを出力を操作。falseを設定した場合、その項目自体が無効化されるためclass自体が出力されない
}
<p className={ toggle ? 'toggle-on' : false }>
  { toggle ? 'toggle ON' : 'toggle OFF' }
</p>

真偽値を手がかりに三項演算子を用いて出し分けていますが、falseにすることでclassの出力自体を無効化できます。

なお、以下のようにすればclassNameの併用も可能ではあります。


<p className={ toggle ? className + ' myclass' : className }>
  { toggle ? 'toggle ON' : 'toggle OFF' }
</p>

恐らくclassName自体に値を追加のが正規の方法なのかなと思われますが、現時点でその方法を調べてきれていませんので、上記の方法はあまり良くない方法かもしれません。

関連記事

Gutenberg(ブロックエディタ)に関連する記事一覧。

2人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄