トップへ戻る
BLOGS

WordPress 既存のブロックスタイルをカスタマイズする

WordPress 既存のブロックスタイルをカスタマイズする

今までたくさんカスタムブロックを作成してきましたが、これまではいわゆる「オリジナルブロック」と呼ばれるもので、テーマに存在するわけではなく、プラグインファイルとして追加して機能するものでした

記事は取得できませんでした

これは一からブロックを定義、登録して開発していくものでしたが、そもそもオリジナルのテーマで開発しているため、通常のデフォルトブロックがさみしいもので、イマイチ機能的に優れているわけではなかったため、そろそろ既存のブロックを拡張した開発がしたいと考えていました

ブロックカスタムスクリプトの登録

今回はテーマに読み込ませる為、functions.phpにて、登録設定用のJSファイルをエンキューします

functions.php

<?php
// カスタムブロック登録用スクリプト
add_action( 'enqueue_block_editor_assets', function () {
	wp_enqueue_script( 'custom_block_editor', get_theme_file_uri( 'js/editor.js'), [
		'wp-element',
		'wp-rich-text',
		'wp-editor',
	]);
	wp_localize_script( 'custom_block_editor', 'ojaEditorObj', [
		[
			'item' => 'editor01',
			'title' => 'marker',
			'class' => 'text-marker',
		],
	]);
});

wp_enqueue_script関数の第3パラメータに依存関係があるパッケージ名を指定します。wp-rich-textだけでも問題なく動作すると思われますが、念の為他の項目も追加しています

ちなみにプラグインで登録する場合にはブロック登録用のPHPに記述すればOKです

この依存スクリプトから、オブジェクトを受け取って処理を書いていくイメージです

editor.js

(function (richText, element, editor) {
// ここに設定を追加していきます。
}(
  window.wp.richText,
  window.wp.element,
  window.wp.editor
));

この書き方はテーマに追加する場合で公式にあるように、ブロックをプラグインとして追加する場合にはモジュールとして読み込みます

import { registerFormatType, toggleFormat } from'@wordpress/rich-text';
import { RichTextToolbarButton } from'@wordpress/block-editor';

wp_localize_script (PHPから値を渡す)

wp_localize_scriptはPHPからJavaScriptに対して値を渡せる便利なメソッドです

wp_localize_script(登録したJSのハンドル名, JSで使用する変数名, JSに渡す値の連想配列)

次はJavaScriptでブロックをラップする方法を見ていきます

registerFormatType

まずはリッチテキスト選択した範囲のテキストにHTMLのタグでラップ出来るようにしてみましょう

公式で以下の書式設定による方法が有効なうようです
書式ツールバー API

書式を登録.js

registerFormatType( 'my-custom-format/sample-output', {
    title: 'Sample output',
    tagName: 'samp',
    className: null,
 edit: SampleEventHandle
} );

richText.registerFormatType関数は、リッチテキストに文字修飾行うHTMLを含む書式を登録する関数です。リッチテキストの選択範囲に対して何らかの処理を行う場合はこの関数が良さそうです。

registerFormatType関数の第1パラメータには文字修飾のタイプ名を「〇〇/〇〇」の形式でユニークなものを指定します
もしタイプ名が「/」で挟まれていない場合はエラーになるので注意が必要です

registerFormatType関数の第2パラメータには文字修飾の設定内容を示すオブジェクトを指定する。オブジェクトの内容としては、
titleには文字修飾の名前を、tagNameには選択範囲を囲むHTML要素の名前を指定する。
classNameにはそのHTML要素のclass属性値を指定し、class属性が不要な場合はnullを指定しないとエラーになるようです。
editには文字修飾を変更する関数(イベントハンドラ)を指定する。

editプロパティ

editプロパティは、フォーカスをあたったり、文字が入力されたりといった多くのタイミングで頻繁に呼び出されるReactのライフサイクルといった内容のようです。

ここで定義するのは、ツールバーを利用したボタンと、その振る舞い(クリックイベント)を登録します
処理内容としては、propsというパラメータを受け取り、wp.element.createElement関数でUI要素を生成して、それを返します

RichTextToolbarButton

RichTextToolbarButtonはツールバーのドロップダウンメニューを提供してくれます

editor.js

return element.createElement(editor.RichTextToolbarButton, {
  icon: "admin-customizer",
  title: ojaEditorObj[0].title,
  onClick: () => {
    onChange(
      richText.toggleFormat(value, {
        type: `custom-editor/${ojaEditorObj[0].item}`,
      })
    );
  },
  isActive: isActive,
});

createElement関数の第2パラメータには、生成するUI要素の設定内容をオブジェクトで指定します

オブジェクトの内容としてiconにはアイコン名(dashiconsのクラス名から先頭の’dashicons-‘を取ったもの)を、titleにはメニューに表示される名前を指定する。
メニュー内容の表示位置は、titleの内容でソートされるようです

onClickにはメニューがクリックされた際に呼び出されるイベントハンドラを指定します
このイベントハンドラでは、richText.toggleFormat関数を使ってスイッチの要素、
「HTML要素で囲む/HTML要素を外すの」トグル処理した内容をprops.onChange関数を呼び出してリッチテキストを更新するようにします
その後、isActiveを呼び出し、リッチテキストにフォーカスを移すようにしています。

そしてcreateElement関数の第3パラメータには子要素を指定できるが、ツールバーのボタンやメニューの場合はそのような要素が不要なため、今回は省略しています

テキストマーカーブロック

今回作成した選択したテキストにマーカーを引くブロックの全文です

editor.js

(function (richText, element, editor) {
  richText.registerFormatType(`custom-editor/${ojaEditorObj[0].item}`, {
    title: ojaEditorObj[0].title,
    tagName: "span",
    className: ojaEditorObj[0].class,
    edit: function ({ isActive, onChange, value }) {
      return element.createElement(editor.RichTextToolbarButton, {
        icon: "admin-customizer",
        title: ojaEditorObj[0].title,
        onClick: () => {
          onChange(
            richText.toggleFormat(value, {
              type: `custom-editor/${ojaEditorObj[0].item}`,
            })
          );
        },
        isActive: isActive,
      });
    },
  });
})(window.wp.richText, window.wp.element, window.wp.editor);

ここまでの書き方はほぼテンプレートのようなもので、必要に応じて項目をカスタマイズすることで機能の追加は可能だと思います

これで、ツールバーにボタンが追加されており、これをクリックすると指定した「spanタグ」に「text-marker」クラスを付与した状態でラップする実装が完了しました
後は、このクラス名に実際にスタイリングを行います

マーカーのスタイリング

editor.scss

// カスタムマーカー
.text-marker {
  background: linear-gradient(to top, #eaeb16 40%, transparent 40%);
  font-weight: bold;
}

既存のブロックにスタイルを追加する

ここからは別のアプローチとして、インスペクターに(管理画面右のサイドバー)にスタイル設定を追加する方法を見ていきます
この方法を使用すれば、どのようなブロックでも簡単にスタイリングをカスタマイズすることが可能です
登録使用するスクリプトファイルは上記で使用したeditor.jsに追記していきます

今回例としてカスタマイズするのは誰もが使用するであろう「見出しブロック」にスタイリングを追加して行こうと思います

早速、これより下記の「見出しブロック」には今回実装したスタイリングにて変更した状態のブロックで追加しております。 気になるスタイルのブロックがあったら最終のコードをコピペすることで実装できますよ(^^)

registerBlockStyle

registerBlockStyle関数はその名の通りブロックに対して、スタイルを生成する関数で、以下の書式で動作します

wp.blocks.registerBlockStyle("名前空間/ブロック名", {
  name: "クラス名",
  label: "デフォルト",
  isDefault: true, //初期状態
});

第2引数の name プロパティの値が「is-style-○○」という形で対象のブロックに付与されます

たったこれだけでブロックに対してクラス名のつけ外しが可能なので、ほとんどの場合この関数だけでまかなえるかもしれません

見出しの種類をカスタマイズ

registerBlockStyle関数を使用して記事を書く際に必ず使用する見出しタグ(core/heading)に対してたくさんの種類から選択できるようなカスタマイズを実装してみます

editor.js

// 見出しにスタイルを追加
wp.blocks.registerBlockStyle("core/heading", {
  name: "drop-itaric",
  label: "一文字目拡大、斜体",
  isDefault: false,
});
wp.blocks.registerBlockStyle("core/heading", {
  name: "simple-line",
  label: "シンプルライン",
  isDefault: true,
});
wp.blocks.registerBlockStyle("core/heading", {
  name: "top-bottom-line",
  label: "上下ボーダー",
  isDefault: false,
});
wp.blocks.registerBlockStyle("core/heading", {
  name: "left-border",
  label: "左垂直ライン",
  isDefault: false,
});
wp.blocks.registerBlockStyle("core/heading", {
  name: "speech-bubble",
  label: "吹き出し",
  isDefault: false,
});
wp.blocks.registerBlockStyle("core/heading", {
  name: "speech-line",
  label: "斜め線吹き出し",
  isDefault: false,
});
wp.blocks.registerBlockStyle("core/heading", {
  name: "two-tone",
  label: "ツートーンカラー",
  isDefault: false,
});
wp.blocks.registerBlockStyle("core/heading", {
  name: "two-tone-circle",
  label: "ツートーンサークル",
  isDefault: false,
});

後は、これに対して実際にスタイリングを行います
ここでCSSを当てるだけで、Reactによるプレビューがマウスオーバーで行われます
WordPressすげー

editor.scss

@import "../../config/config";
@import "../../config/mixin";
h1, h2, h3, h4, h5, h6 {
  margin: 2em 0 1em;
  font-weight: bold;
  line-height: 1.6;
  color: #847d76;

  // シンプルライン
  &:not(h1) {
    position: relative;
    font-weight: 400;
    color: $text_color;
    &::before, &::after {
      position: absolute;
      content: "";
      z-index: 0;
      bottom: 0;
      left: 0;
      top: initial !important;
    }
    &::before {
      width: 100%;
      height: 2px;
      border-radius: 1px;
      background: $sub_color;
      opacity: .5;
    }
    &::after {
      width: 20%;
      height: 2px;
      border-bottom-left-radius: 1px;
      border-top-left-radius: 1px;
      background: $main_color;
    }
  }

  // ドロップキャップ、イタリック
  &.is-style-drop-itaric {
    color: $main_color;
    border-bottom: 3px solid $main_color;
    transform: skew(-15deg, 0deg);
    &:first-letter {
      font-size: 2.2rem;
      color: $main_color;
      @include md {
        font-size: 1.85rem;
      }
    }
    &::before, &::after {
      content: none;
    }
  }

  // 上下ボーダー
  &.is-style-top-bottom-line{
    border-top: 2px solid $text_color;
    border-bottom: 2px solid $text_color;
    &::before, &::after {
      content: none;
    }
  }

  // 左垂直ライン
  &.is-style-left-border{
    border-left: 6px solid rgba($main_color, 0.8);
    padding: 12px 15px 12px 10px;
    @include sm {
      border-left: 4px solid rgba($main_color, 0.8);
      padding: 8px 10px 8px 10px;
    }
    &::after {
      content: none;
    }
  }

  // 吹き出し
  &.is-style-speech-bubble {
    padding: 1rem 2rem;
    border-radius: 10px;
    background: rgba($main_color, 0.4);
    color: #fff;
    @include sm {
      padding: 0.8rem 1.6rem;
    }
    &::before {
      content: none;
    }
    &::after {
      width: 0;
      height: 0;
      bottom: -10px;
      left: 1.5em;
      border-width: 10px 10px 0 10px;
      border-style: solid;
      border-color: rgba($main_color, 0.4) transparent transparent transparent;
      background: none;
    }
  }

  // 斜め線吹き出し
  &.is-style-speech-line {
    display: inline-block;
    padding: 3px 60px;
    margin-top: 3%;
    margin-left: 16%;
    margin-right: 16%;
    @include sm {
      padding: 3px 45px;
      margin-left: 10%;
      margin-right: 10%;
    }
    &::before, &::after {
      top: 50% !important;
      display: inline-block;
      width: 45px;
      bottom: initial;
      background: $main_color;
      height: 2px;
      @include sm {
        width: 40px;
      }
    }
    &::before {
      left:0;
      transform: rotate(60deg);
      opacity: 1;
    }
    &::after {
      left: initial;
      right: 0;
      transform: rotate(-60deg);
    }
  }

  // ツートーン
  &.is-style-two-tone {
    color: #fff;
    padding: 12px 10px 12px 17px;
    background: linear-gradient(rgba($main_color, 0.4), 0%, rgba($main_color,.8)  50%, rgba($main_color,1)  50%) ;
    border-radius: 50em 50em 50em 50em;
    &::before, &::after {
      content: none;
    }
  }

  // ツートーンサークル
  &.is-style-two-tone-circle {
    &::before {
      width: 50px;
      height: 50px;
      border-radius: 50%;
      background: #F8D76A;
      opacity: .4;
      bottom: initial;
      top: 10px !important;
      left: -7px;
      @include sm {
        width: 40px;
        height: 40px;
      }
    }
    &::after {
      width: 42px;
      height: 42px;
      border-radius: 50%;
      background: $main_color;
      opacity: 0.1;
      bottom: 15px;
      left: 16px;
      @include sm {
        width: 32px;
        height: 32px;
      }
    }
  }
  
} //h1, h2, h3, h4, h5, h6

// ベーススタイリング
h1 {
  font-size: 1.8rem;
  line-height: 2.3rem;
  font-weight: 400;
  @include lg {
    font-size: 1.6rem;
  }
  @include md {
    font-size: 1.5rem;
  }
}
h2 {
  font-size: 1.65rem;
  line-height: 2rem;
  padding: 15px 15px 10px 8px;
  margin-top: 2.6rem;
  margin-bottom: 1.6rem;
  @include md {
    font-size: 1.45rem;
    line-height: 1.8rem;
    padding: 13px 13px 8px 6px;
    margin-top: 1.4rem;
    margin-bottom: 1rem;
    font-weight: 700;
  }
  @include sm {
    font-size: 1.2rem;
  }
}
h3 {
  font-size: 1.5rem;
  line-height: 2rem;
  padding: 12px 20px;
  margin-top: 2.3rem;
  margin-bottom: 1.6rem;
  font-weight: 400;
  @include md {
    font-size: 1.2rem;
    line-height: 1.7rem;
    padding: 10px 15px;
    margin-top: 1.4rem;
    margin-bottom: 1rem;
    font-weight: 700;
  }
}
h4 {
  font-size: 1.3rem;
  line-height: 1.8rem;
  padding: 8px 15px;
  margin-top: 1rem;
  margin-bottom: 0.8rem;
  @include md {
    font-size: 1.1rem;
    line-height: 1.6rem;
    padding: 6px 8px;
    margin-top: 1rem;
    margin-bottom: 0.8rem;
    font-weight: 700;
  }
}
h5 {
  font-size: 14px;
  letter-spacing: 1.5px;
  padding-left: 20px;
  color: $sub_color;
  @include md {
    font-size: 15px;
  }
}
h6 {
  font-size: 12px;
  padding-left: 20px;
}

CSSは私のセンスですのでもちろん変更は簡単にできます

今回学んだ内容

今回は簡単な内容にて進めやすくほぼコピペでOKな内容でしたが、
やはり既存のブロックカスタムを極めてからオリジナルのブロック開発へ進むのが公式的にも望ましいようですので、もう少し掘り下げて頑張ってみます

registerBlockStyleに思うこと

オリジナルのスタイリングの登録は非常に簡単で少しCSSの知識がある人であれば簡単にスタイリングを追加変更できるのは、 WordPress流石です。

欲を言うのであれば、この関数を実行すると対象のブロックに対して自動でインスペクター(設定を行うサイドバー)も表示されますが、 これに対して出力されるコンポーネントに追加のクラス名などを挿入したい場合、どうしていいものか簡単に調べただけでは見つけることができませんでした。

例えば、出力されるボタンに設定するクラス名を付与しておきそのボタン自体のスタイルを対象のスタイルと同じにして、見た目をわかりやすくしたりなど改善していきたいです

registerFormatTypeの所感

ツールバーに項目を追加して選択したテキストをマークアップするのはまだまだ奥ゆかしい知識が必要そうで、これからもっと使いやすくするためのアップデートにてより深く学んでいこうと思いました

書式APIとして用意されているこの関数を使用して他にも面白いカスタマイズはあるでしょう。

今回は初めての使用でまだ理解がふわついていますがこれから使いこなしていきます

お疲れさまでした

コメントをお待ちしております

お気軽にコメントをどうぞ。

CAPTCHA