MTAppjQuery の mtapp.multiField v2 に独自のフィールドを追加してみよう

こんにちは。この記事は「Movable Type Advent Calendar 2021」6日目の記事です。MTのアドベントカレンダーが始まってから、今年でついに10年連続で12月6日に投稿しています。そんな僕ももう45歳。。。

さて、気を取り直して今日は MTAppjQuery v2.7.0 で追加された mtapp.multiField v2 に独自のフィールドを追加する方法をご紹介します。

仕様

記事等に関連情報を付けるフィールドを想定してみます。入力する項目は下記のようにしてみましょう。

  • リンクのラベル(テキスト)
  • リンクの種類を「リンク」「ファイル」「画像」から選択
  • リンクの種類が「リンク」のとき:URLを入力
  • リンクの種類が「ファイル」のとき:アセットフィールドを表示
  • リンクの種類が「画像」のとき:画像フィールドを表示

作成するフィールドの定義を追加

まず user.jsmtapp.multiField()fieldBlocks オプションに作成するフィールドの定義を追加します。

今回はrelatedContent というハンドルのフィールドを追加します。なお、version: 2 オプションを忘れないようにしてください。

(function($){
  'use strict';

  mtapp.multiField({
    version: 2, // 忘れないように!
    label: 'マルチフィールド',
    showViewRawDataButton: true,
    id: 72, // 適宜変更してください。
    fieldBlocks: {
      relatedContent: {
        type: 'relatedContent',
        label: '関連コンテンツ',
        data: {
          relatedContentLabel: '',
          relatedContentType: '',
          relatedContentFile: {},
          relatedContentImage: {}
        }
      },
    },
    // fieldGroups は配列
    fieldGroups: [
      [
        'text', 'relatedContent'
      ]
    ]
  });

})(jQuery);

これで、デフォルトで用意されている1行テキストの「テキスト」フィールドと、今回追加する「関連コンテンツ」フィールドの2つのボタンが表示されます。この段階では「関連コンテンツ」ボタンをクリックしても空のフィールドブロックが追加されるだけです。

Clean Shot 2021 12 06 10 52 05

VueComponents というグローバルテンプレートモジュールを作成

ブラウザの別タブでシステムメニューを表示し、システムメニューの左サイドメニューの「デザイン > グローバルテンプレート」に移動します。

画面右上のドロップダウンリストで「テンプレートモジュール」を選択したまま「新規作成」をクリックします。

テンプレート名とテンプレート本体に VueComponents と入れて保存します。すると、画面左上に「VueComponents」と表示されれば成功です。

Clean Shot 2021 12 06 10 56 56

VueComponents グローバルテンプレートモジュールを編集

VueComponents グローバルテンプレートモジュールに、関連コンテンツブロックの大枠を定義した下記の内容をコピペして保存します。

<mt:Ignore>
  VueRelatedContent というコンポーネントのテンプレートを定義
  「関連リンク」ボタンをクリックしたときに追加されるフィールドブロックのテンプレート
</mt:Ignore>
<script type="text/x-template" id="mf-component-relatedContent">
  <div>VueRelatedContent</div>
</script>

<mt:Ignore>VueRelatedContent というコンポーネントを定義(Vue.js)</mt:Ignore>
<script>
  Vue.component('VueRelatedContent', {
    props: { item: Object },
    template: '#mf-component-relatedContent'
  });
</script>

<mt:Ignore>type: 'relatedContent' のときに上記フィールドブロックが表示されるように MTAppjQuery に追加</mt:Ignore>
<mt:SetVarBlock name="mtapp_mf_additional_fields">
  <template v-else-if="fieldBlocks[item.handle].type === 'relatedContent'">
    <VueRelatedContent></VueRelatedContent>
  </template>
</mt:SetVarBlock>

この状態で「関連コンテンツ」ボタンをクリックすると下図のように表示されます。

Clean Shot 2021 12 06 11 17 55

ポイントは下記の項目を間違えないようにすることです。

  • type で指定する値と同じものを入れる(赤)
  • 上記の type で指定する値の先頭に Vue をつけてパスカルケースにする(オレンジ)
  • v-else-if にする(緑)
Clean Shot 2021 12 06 11 19 56

VueRelatedContent コンポーネントの中身を作成

VueRelatedContent コンポーネントの中身を下記のようにしてみました。

<mt:Ignore>
  VueRelatedContent というコンポーネントのテンプレートを定義
  「関連コンテンツ」ボタンをクリックしたときに追加されるフィールドブロックのテンプレート
</mt:Ignore>
<script type="text/x-template" id="mf-component-relatedContent">
  <div>
    <div class="mb-4">
      <label class="d-block">リンクのラベル</label>
      <input type="text" class="form-control" v-model="item.data.relatedContentLabel">
    </div>
    <div class="mb-4">
      <label class="d-block">リンクのタイプ</label>
      <select class="custom-select form-control" v-model="item.data.relatedContentType">
        <option value=""></option>
        <option value="link">リンク</option>
        <option value="file">ファイル</option>
        <option value="image">画像</option>
      </select>
    </div>

    <div class="mb-4" v-if="item.data.relatedContentType === 'link'">
      <label class="d-block">URL</label>
      <input type="url" class="form-control" v-model="item.data.relatedContentUrl">
    </div>
    <div class="mb-4" v-else-if="item.data.relatedContentType === 'file'">
      <label class="d-block">ファイル</label>
      <VueInnerAsset
        :id="[item.id, 'relatedContentFile'].join('-')"
        :item="item"
        :storage="item.data"
        :handle="'relatedContentFile'"
        :fieldBlock="fieldBlocks['asset']" />
    </div>
    <div class="mb-4" v-else-if="item.data.relatedContentType === 'image'">
      <label class="d-block">画像</label>
      <VueInnerAsset
        :id="[item.id, 'relatedContentImage'].join('-')"
        :item="item"
        :storage="item.data"
        :handle="'relatedContentImage'"
        :fieldBlock="fieldBlocks['image']" />
    </div>
  </div>
</script>

<mt:Ignore>VueRelatedContent というコンポーネントを定義(Vue.js)</mt:Ignore>
<script>
  Vue.component('VueRelatedContent', {
    props: { item: Object, version: Number, fieldBlocks: Object },
    template: '#mf-component-relatedContent'
  });
</script>

<mt:Ignore>type: 'relatedContent' のときに上記フィールドブロックが表示されるように MTAppjQuery に追加</mt:Ignore>
<mt:SetVarBlock name="mtapp_mf_additional_fields">
  <template v-else-if="fieldBlocks[item.handle].type === 'relatedContent'">
    <VueRelatedContent :item="item" :version="version" :fieldBlocks="fieldBlocks"></VueRelatedContent>
  </template>
</mt:SetVarBlock>

出来上がったフィールド

これで下図のような動きのフィールドが出来ました。

保存されるデータ

このフィールドで保存されるデータは下記のようになります。

{
   "items":[
      {
         "data":{
            "relatedContentLabel":"今日のリンク(リンク)",
            "relatedContentType":"link",
            "relatedContentFile":{},
            "relatedContentImage":{},
            "relatedContentUrl":"https://tinybeans.net"
         },
         "handle":"relatedContent",
         "id":"WeL3y80d"
      },
      {
         "data":{
            "relatedContentLabel":"今日のリンク(ファイル)",
            "relatedContentType":"file",
            "relatedContentFile":{
               "id":"71",
               "url":"/relatedcontent/0319119334403d04dda975cc67a14decbff4d9f2.pdf"
            },
            "relatedContentImage":{}
         },
         "handle":"relatedContent",
         "id":"GrRur7Oy"
      },
      {
         "data":{
            "relatedContentLabel":"今日のリンク(画像)",
            "relatedContentType":"image",
            "relatedContentFile":{},
            "relatedContentImage":{
               "id":"72",
               "url":"/relatedcontent/08b069c7e6eb73c62ea7ead0d948399e93ddfd80.jpg",
               "thumbnail":"/relatedcontent/assets_c/2021/12/08b069c7e6eb73c62ea7ead0d948399e93ddfd80-thumb-120xauto-72.jpg"
            }
         },
         "handle":"relatedContent",
         "id":"hHspx1CK"
      }
   ],
   "version":2,
   "ts":1638749765476
}

以上となります。

細かい解説は、、、必要でしたらサポートにお問い合わせください!

今後はもう少しオリジナルフィールドを楽に追加出来るようにしていきたいと思っています。

MTAppjQuery について

Movable Type の管理画面をフロントエンドの知識だけで簡単にカスタマイズすることができます。

クライアントの満足度を高めるためにぜひお使いください。

MTAppjQuery の詳細を見る

MTAppjQuery