🐣

microCMS拡張フィールド連携機能: 利用手順と実装方法

2024/05/10に公開

当記事について

本記事では、microCMSの拡張フィールド機能について、その利用手順や実装内容を詳細に調査し、その結果をまとめています。
公式サイトの説明記事(https://document.microcms.io/manual/field-extension)から機能の概要を理解していただくことを前提としています。

利用手順

①microCMS管理画面>API設定>APIスキーマ>フィールドを追加ボタン押下する。

②拡張フィールド用外部連携用サイト※のURLを入力。

③サイトに実装したオリジナルの入力UIが表示される。

コンテンツに拡張フィールド項目がありに更新される。

実装方法

microCMSの管理画面上で拡張フィールドを利用するためには、専用のWebサイトを開発して外部連携する必要があります。
一見敷居が高く感じるかもしれませんが、特定の仕様に準拠していれば、表示内容は自由に設定できるため幅広い目的に対応可能になります。
本記事の実装例では、公式の説明記事(https://blog.microcms.io/iframe-table/)をベースに記載しています。

①messageイベントリスナーの設置
拡張フィールドが設定されているmicroCMSの管理画面上でコンテンツ作成/編集画面を開くと、messageイベントが発火します。
これに対してイベントリスナーを設置し、microCMSから送信される識別IDと既存の設定値を受け取る必要があります。

window.addEventListener('message', (e) => {
  if (
    e.isTrusted === true &&
    e.data.action === 'MICROCMS_GET_DEFAULT_DATA'
  ) {
       // eの内容
       // e.data.id: iframe識別子
       // e.data.message: 設定済みの値
       // e.data.user.email ログイン中のユーザーメールアドレス情報
       setState({
           iframeId: e.data.id,
           defaultMessage: e.data.message,
       });
    }
});

②postMessage処理の設置
管理画面に値を入力して保存した際に、microCMS側に送信するためのpostMessage処理を記述します。

window.parent.postMessage(
  {
    id: state.iframeId,  // iframe識別子
    action: 'MICROCMS_POST_DATA',
    message: {
          data:{ 
              editorContent, // 入力値
          }
    }
  },
  'https://XXXX.microcms.io' // 利用するmicroCMS管理画面URLを記述してください。
);

/Editor.jsx
import { useState, useEffect } from "react";
import { useEditor, EditorContent } from "@tiptap/react";
import Document from "@tiptap/extension-document";
import Paragraph from "@tiptap/extension-paragraph";
import Text from "@tiptap/extension-text";
import Table from "@tiptap/extension-table";
import TableRow from "@tiptap/extension-table-row";
import TableCell from "@tiptap/extension-table-cell";
import TableHeader from "@tiptap/extension-table-header";
import Gapcursor from "@tiptap/extension-gapcursor";
import Bold from "@tiptap/extension-bold";

// icon
import AddColBefore from "./icon/add_col_before.svg";
import AddColAfter from "./icon/add_col_after.svg";
import DeleteCol from "./icon/delete_col.svg";
import ChangeThCol from "./icon/change_th_col.svg";
import AddRowBefore from "./icon/add_row_before.svg";
import AddRowAfter from "./icon/add_row_after.svg";
import DeleteRow from "./icon/delete_row.svg";
import ChangeThRow from "./icon/change_th_row.svg";
import CombineCells from "./icon/combine_cells.svg";
import BoldIcon from "./icon/bold.svg";

// CSS
import "./css/Editor.scss";

const microcmsAdminUrl = "https:"; // ここに利用するmicroCMS管理画面URLを記述してください。

export const Editor = () => {
  const [state, setState] = useState({
    iframeId: "",
    defaultMessage: {},
  });

  useEffect(() => {
    window.addEventListener("message", (e) => {
      if (
        e.isTrusted === true &&
        e.data.action === "MICROCMS_GET_DEFAULT_DATA"
      ) {
        setState({
          iframeId: e.data.id,
          defaultMessage: e.data.message,
        });

        window.parent.postMessage(
          {
            id: e.data.id,
            action: "MICROCMS_UPDATE_STYLE",
            message: {
              height: 300,
            },
          },
          microcmsAdminUrl
        );
      }
    });
  }, []);

  const postDataToMicroCMS = (editorContent) => {
    window.parent.postMessage(
      {
        id: state.iframeId,
        action: "MICROCMS_POST_DATA",
        message: {
          data: editorContent,
        },
      },
      microcmsAdminUrl
    );
  };

  const editor = useEditor(
    {
      extensions: [
        Document,
        Paragraph,
        Text,
        Bold,
        Gapcursor,
        Table.configure({
          resizable: true,
        }),
        TableRow,
        TableHeader,
        TableCell,
      ],
      content: `
        <table>
          <tbody>
            <tr>
              <td></td>
              <td></td>
              <td></td>
              <td></td>
            </tr>
            <tr>
              <td></td>
              <td></td>
              <td></td>
              <td></td>
            </tr>
            <tr>
              <td></td>
              <td></td>
              <td></td>
              <td></td>
            </tr>
          </tbody>
        </table>
    `,
      onCreate({ editor }) {
        if (Object.keys(state.defaultMessage).length) {
          editor.commands.setContent(state.defaultMessage.data);
        }
      },
      onUpdate({ editor }) {
        postDataToMicroCMS(editor.getHTML());
      },
    },
    [state.defaultMessage]
  );

  if (!editor) {
    return null;
  }

  return (
    <div className="editor">
      <div className="toolbar">
        <button
          onClick={() => editor.chain().focus().toggleBold().run()}
          className={editor.isActive("bold") ? "is-active" : ""}
        >
          <img src={BoldIcon} />
        </button>
        <button onClick={() => editor.chain().focus().mergeOrSplit().run()}>
          <img src={CombineCells} />
        </button>
        <button onClick={() => editor.chain().focus().addColumnBefore().run()}>
          <img src={AddColBefore} />
        </button>
        <button onClick={() => editor.chain().focus().addColumnAfter().run()}>
          <img src={AddColAfter} />
        </button>
        <button onClick={() => editor.chain().focus().deleteColumn().run()}>
          <img src={DeleteCol} />
        </button>
        <button
          onClick={() => editor.chain().focus().toggleHeaderColumn().run()}
        >
          <img src={ChangeThCol} />
        </button>
        <button onClick={() => editor.chain().focus().addRowBefore().run()}>
          <img src={AddRowBefore} />
        </button>
        <button onClick={() => editor.chain().focus().addRowAfter().run()}>
          <img src={AddRowAfter} />
        </button>
        <button onClick={() => editor.chain().focus().deleteRow().run()}>
          <img src={DeleteRow} />
        </button>
        <button onClick={() => editor.chain().focus().toggleHeaderRow().run()}>
          <img src={ChangeThRow} />
        </button>
      </div>
      <div className="editor-content">
        <EditorContent editor={editor} />
      </div>
    </div>
  );
};

/App.js
import { Editor } from './Editor.jsx'
import './css/App.scss';

const App = () => {
  return (
    <div className="App">
      <Editor />
    </div>
  )
}

export default App;

ローカルアクセスしてテーブルUIのみの画面が表示できていれば実装完了になります。

株式会社トッカシステムズ

Discussion