News

お知らせ

Information

WordPressのカスタムブロックを作ろう

WordPressのブロックエディターはモジュール化されたブロックによって、統一感の生まれるコンテンツを作りやすくなっています。
また、エディターにCSSをそのまま適用することにより、作成したコンテンツとの差異が少なく、コンテンツ作成に慣れていない人でも使いやすいものになっています。
ブロックはWordPressのコアにいくつか用意されている他、プラグインなどで新しく導入することが可能です。

今回はテーマ独自のブロック(カスタムブロック)を組み込む方法について記事にしました。

カスタムブロックを作成するには

WordPressでカスタムブロックを作成するにはいくつかの方法が存在しています。

  • カスタムブロックを作成できるプラグインを導入する(例:Genesis Custom Blockなど)
  • @wordpress/create-blockを利用したプラグイン化
  • 直接テーマファイルで記述する方法

カスタムブロックを作成できるプラグインを導入すると、簡単にカスタムブロックが作成できます。ただ、ある程度制限があり複雑なブロックの作成は難しいです。

@wordpress/create-blockを利用した作成方法は、Node.js環境を利用し、ブロックをJSXで作成・プラグイン化するものです。JSXを活用し記述することができますが、作成したプラグインをトランスパイルする必要があり、少々手間な部分が存在します。

今回は3つ目の「直接テーマファイルで記述する方法」を用いてカスタムブロックを作成します。JavaScriptを使用するため、@wordpress/create-blockを用いた方法と似たようなものが作成可能です。

カスタムブロックに必要なもの

カスタムブロックをテーマに導入するために必要なものは

  • functions.phpへの記述
  • cssファイルの用意
  • jsファイルの用意

の3つです。
それぞれ順番に作成していきましょう。
今回はアコーディオンブロック(<details>を利用)を作成してみます。

functions.php

まずはfunctions.phpcssファイルやjsファイルを読み込んで、ブロックを機能させる記述を行います。

PHP
if (!function_exists('block_path')) {
  /**
   * Blocksディレクトリへのパス
   *
   * @param {string} $path
   */
  function block_path($path = '')
  {
    return get_stylesheet_directory_uri() . '/blocks/' . $path;
  }
}

if (!function_exists('initialize_custom_blocks')) {
  /**
   * 指定したディレクトリのブロックを登録する
   * ※エディター画面
   */
  function initialize_custom_blocks() {
    $blocks = ['accordion'];

    foreach ($blocks as $block) {
      wp_enqueue_style( 'custom-button-style', block_path("$block/block.css"));
      wp_enqueue_script( 'custom-button-script', block_path("$block/block.js") ,['wp-blocks', 'wp-dom'], '', true);
    }
  }
  add_action('enqueue_block_assets', 'initialize_custom_blocks');

  /**
   * 指定したディレクトリのブロックのCSSを登録する
   */
  function add_block_css()
  {
    if (!is_admin()) {
      $blocks = ['accordion'];
      $theme =  wp_get_theme();

      foreach ($blocks as $block) {
        wp_enqueue_style('custom-button-style', block_path("$block/block.css"), [], $theme->Version);
      }
    }
  }
  add_action('wp_enqueue_scripts', 'add_block_css');
}

テーマフォルダ内にblocksというフォルダを作成します。そこにパスが通るようblock_pathという関数を定義し、使用するcssファイルやjsファイルはそれを用いて記述します。
enqueue_block_editor_assetswp_enqueue_scriptsへのアクションフックでは、cssファイルやjsファイルを必要な箇所で読み込むようにしています。$blocks = ['accordion'];で読み込みたいブロック名(フォルダ名)を指定するようにし、カスタムブロックを追加した際の変更箇所が最低限になるようにしています。

block.js

テーマ/blocks/accordionblock.jsファイルを作成します。このjsファイルでは、ブロックがエディターに表示された時の挙動、保存時のHTMLを定義することができます。

JavaScript
const { registerBlockType } = wp.blocks;
const { createElement } = wp.element;

registerBlockType('custom/accordion', {
  title: "アコーディオン",
  description: "",
  icon: "wordpress",
  category: "text",
  keywords: ["accordion", "アコーディオン"],
  edit: () => {
    return createElement("div", {
      className: "c-accordion",
    }, [
        "text"
    ]),
  },
  save: () => {
    return null
  },
});

editメソッドに必要な記述を行うと、エディターに表示されるようになります。このブロックではdivタグに「text」とだけ文字が表示されます。
一度WordPressのエディターで確かめてみます。

テキストカテゴリーのブロックに「アコーディオン」が追加されており、追加を行うと

このような形で「text」と表示されます。
この状態では固定の文字のみ表示されている状態なので、入力ができるように修正を行います。入力を行うためにはRichTextコンポーネントを使用します。

JavaScript
const { registerBlockType } = wp.blocks;
const { createElement } = wp.element;
const { RichText } = wp.editor;

registerBlockType('custom/accordion', {
  title: "アコーディオン",
  description: "",
  icon: "wordpress",
  category: "text",
  keywords: ["accordion", "アコーディオン"],
  attributes: {
    summary: {
      type: "string",
      source: "html",
      selector: ".c-accordion__summary",
    },
    text: {
      type: "string",
      source: "html",
      selector: ".c-accordion__content",
    },
  },
  edit: ({ attributes, setAttributes }) => {
    function onChangeSummaryText (newValue) {
      setAttributes({ summary: newValue });
    }

    function onChangeContentText (newValue) {
      setAttributes({ text: newValue });
    }

    return createElement("div", {
      className: "c-accordion",
    }, [
      createElement("details", {
        className: "c-accordion__details",
        open: true,
      }, [
        createElement(RichText, {
          className: "c-accordion__summary",
          tagName: "summary",
          onChange: onChangeSummaryText,
          value: attributes.summary,
        }),
        createElement(RichText, {
          className: "c-accordion__content",
          tagName: "div",
          onChange: onChangeContentText,
          value: attributes.text,
        }),
      ]),
    ]);
  },
  save: () => {
    return null;
  },
});

JSXではなくcreateElementを使用しなければならないので、HTMLの構造がわかりづらい部分はありますが、createElementの第三引数(配列)にネストすることで、対象の子要素に入れることができます。
WordPressのエディターで確認すると

入力が行うことができるようになっています。
しかし現状では保存した時の挙動が

JavaScript
save: () => {
    return null;
}

となっているため、保存しても何も起きません。
次は入力した内容をsaveメソッドで保存できるようにします。

JavaScript
const { registerBlockType } = wp.blocks;
const { createElement } = wp.element;
const { RichText } = wp.editor;

registerBlockType('custom/accordion', {
  title: "アコーディオン",
  description: "",
  icon: "wordpress",
  category: "text",
  keywords: ["accordion", "アコーディオン"],
  attributes: {
    summary: {
      type: "string",
      source: "html",
      selector: ".c-accordion__summary",
    },
    text: {
      type: "string",
      source: "html",
      selector: ".c-accordion__content",
    },
  },
  edit: ({ attributes, setAttributes }) => {
    function onChangeSummaryText (newValue) {
      setAttributes({ summary: newValue });
    }

    function onChangeContentText (newValue) {
      setAttributes({ text: newValue });
    }

    return createElement("div", {
      className: "c-accordion",
    }, [
      createElement("details", {
        className: "c-accordion__details",
        open: true,
      }, [
        createElement(RichText, {
          className: "c-accordion__summary",
          tagName: "summary",
          onChange: onChangeSummaryText,
          value: attributes.summary,
        }),
        createElement(RichText, {
          className: "c-accordion__content",
          tagName: "div",
          onChange: onChangeContentText,
          value: attributes.text,
        }),
      ]),
    ]);
  },
  save: ({ attributes }) => {
    return createElement("div", {
      className: "c-accordion",
    }, [
      createElement("details", {
        className: "c-accordion__details",
      }, [
        createElement("summary", {
          className: "c-accordion__summary",
        }, [
          attributes.summary,
        ]),
        createElement("div", {
          className: "c-accordion__content",
        }, [
          attributes.text,
        ]),
      ]),
    ]);
  },
});

saveメソッドもeditメソッドと同じように、createElementを用いて記述を行います。saveでは実際に保存されるHTML構造を基に記述を行います。editメソッドで入力されてる内容は、attributesプロパティから受け取るようにします。editメソッドではインタラクションを行う関係上、divを増やしたりなどといったことも必要な場合があります。

実際に保存されるHTMLは以下のようになっています。

HTML
<!-- wp:custom/accordion -->
<div class="wp-block-custom-accordion c-accordion">
  <details class="c-accordion__details">
    <summary class="c-accordion__summary">アコーディオンタイトル</summary>
    <div class="c-accordion__content">
      アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。
    </div>
  </details>
</div>
<!-- /wp:custom/accordion -->

最後にexampleプロパティも増やしておきましょう。

JavaScript
const { registerBlockType } = wp.blocks;
const { createElement } = wp.element;
const { RichText } = wp.editor;

registerBlockType('custom/accordion', {
  title: "アコーディオン",
  description: "",
  icon: "wordpress",
  category: "text",
  keywords: ["accordion", "アコーディオン"],
  attributes: {
    summary: {
      type: "string",
      source: "html",
      selector: ".c-accordion__summary",
    },
    text: {
      type: "string",
      source: "html",
      selector: ".c-accordion__content",
    },
  },
  example: {
    attributes: {
      summary: "アコーディオンタイトル",
      text: "アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。アコーディオンの内容。",
    },
  },
  edit: ({ attributes, setAttributes }) => {
    function onChangeSummaryText (newValue) {
      setAttributes({ summary: newValue });
    }

    function onChangeContentText (newValue) {
      setAttributes({ text: newValue });
    }

    return createElement("div", {
      className: "c-accordion",
    }, [
      createElement("details", {
        className: "c-accordion__details",
        open: true,
      }, [
        createElement(RichText, {
          className: "c-accordion__summary",
          tagName: "summary",
          onChange: onChangeSummaryText,
          value: attributes.summary,
        }),
        createElement(RichText, {
          className: "c-accordion__content",
          tagName: "div",
          onChange: onChangeContentText,
          value: attributes.text,
        }),
      ]),
    ]);
  },
  save: ({ attributes }) => {
    return createElement("div", {
      className: "c-accordion",
    }, [
      createElement("details", {
        className: "c-accordion__details",
      }, [
        createElement("summary", {
          className: "c-accordion__summary",
        }, [
          attributes.summary,
        ]),
        createElement("div", {
          className: "c-accordion__content",
        }, [
          attributes.text,
        ]),
      ]),
    ]);
  },
});

exampleプロパティを増やすことで、ブロックのプレビュー部分が表示できるようになります。

block.css

最後はスタイリングを行います。テーマ/blocks/accordionblock.cssを作成します。

CSS
.c-accordion {
  padding: 16px;
  background-color: #f2f2f2;
  border-radius: 8px;
}

.c-accordion__summary {
  margin-bottom: 8px;
}

.c-accordion__content {
  padding: 16px;
  background-color: #fff;
  border-radius: 4px;
}

ここは好きにスタイリングしましょう。場合によってはc-accordion__content部分など余白の取り方を変えるために、divを増やしたりなどが必要になるかもしれません。
WordPressのエディターで確認してみます。

無事エディター内で、スタイルが反映された状態で確認することができました。
フロント部分はどうでしょうか。

フロントの詳細画面でもエディターとまったく同じスタイルで適用されています。
もし、WordPressをヘッドレスCMS化しているなら同じスタイルをフロントエンドに適用すれば同じように見えるでしょう。

以上でカスタムブロックの追加を完了しました。

最後に

当社ではこのように実装のサポート等手厚く行っております。ご興味を持っていただけましたら、当社採用情報からご応募いただけますと幸いです。

ご質問等ございましたら、お気軽に当社お問合せよりお問合せください。