マルチフィールドのコンテンツ出力方法

Posted on:2018-12-01

この記事はMTAppjQuery Advent Calendar 2018の1日目の記事です。
祝)今年から始まったMTAppjQueryのAdvent Calendar一発目の記事を書きたいと思います。

初日の内容は、MTAppjQuery 2から実装されたmultiFieldの表示側の取り出し方について書きたいと思います。
user.jsで設定したブロックをどのように取り出すのか参考になればと思います。

MTAppjQuery 2から実装されたmultiFieldでは、好きなレイアウトモジュールのフィールド(グループで組み合わせたり)を任意で設定することができます。※user.jsに好きなフィールドタイプを定義していく形になります。
入力された値はJSONとして保存されるので、MTタグと組み合わせて出力させます。

入力された値は、JSONとして保存されます。
保存された値をテンプレートに出力させるためにはmt:Loopなどループ系のタグを使い取り出します。

mt:Loop の使い方については、以下のドキュメントを参照してみてください。

また、v2.3.0 mt:Foreachmt:NestVar が実装されました。
今回は単純に mt:Loop を回した場合と mt:Foreachmt:NestVar を使った場合の比較したいと思います。
また、サンプルコードでは見た目を整えるために UIkit というCSSフレームワークを使っています。

multiFieldの設定したブロックフィールド

まずは、user.jsに multiField を設定します。
投稿系で考えられる必要最低限のブロックフィールドを用意しておきました。

設定したフィールド

  • 見出し01(h1)
  • 見出し02(h2)
  • 見出し03(h3)
  • テキスト(txt)
  • 複数テキスト(textarea)
  • 画像単体アップロード(img)
  • 表組み(table)
  • リスト(ul)
  • 画像単体アップロード + テキスト(img + text)

user.js Code

user.jsは以下のように設定しています。
設定したフィールドは mtapp.multiField の部分のように記述します。
multiFieldの設定では、id は必須になるため .nav-tabs の部分でフィールドをeachで回して特定のフィールド名の id を取得して関数を実行するようにしています。
この処理を加えておくことで本番・開発環境でのidの差異をなくすために記述しています。

"use strict";

var DEMO_MT7 = {};
var demo_mt7;

DEMO_MT7 = function () {
  this.init();
};

(function ($, window, document, undefined) {
  /*
   * ==================================================
   * NOTE: config
   * ==================================================
   */

  DEMO_MT7.prototype = {
    /*
     * 初期設定
     */
    init: function () {
      var self = this;

      $(".nav-tabs").each(function () {
        var id = $(this).prop("id");
        var number = id.match(/(\d+)/g);
        var label_text = $(this).find("label").text().trim();
        if (label_text === "マルチフィールド") {
          multiFieldFunc(number);
        }
      });

      function multiFieldFunc(id) {
        mtapp.multiField({
          debug: false,
          id: id,
          label: "マルチフィールド",
          fieldGroups: [
            [
              { type: "h1", label: "見出し01" },
              { type: "h2", label: "見出し02" },
              { type: "h3", label: "見出し03" },
            ],
            [
              { type: "text", label: "1行テキスト" },
              { type: "textarea", label: "複数行テキスト", rows: 8 },
              { type: "image", label: "画像単体アップロード" },
            ],
            [
              {
                type: "table",
                label: "表組み",
                options: [
                  { type: "text", label: "見出し" },
                  { type: "textarea", label: "テキスト" },
                ],
              },
              {
                type: "table",
                label: "リスト",
                options: [
                  { type: "url", label: "URL" },
                  { type: "text", label: "テキスト" },
                ],
              },
            ],
            [
              {
                type: "multi-column-content",
                label: "画像単体アップロード + テキスト",
                options: [
                  [{ type: "text", label: "キャプション" }],
                  [{ type: "image", label: "画像" }],
                ],
              },
            ],
          ],
        });
      }
    },
  };
})(jQuery, window, document);
demo_mt7 = new DEMO_MT7();

例)MovableType標準タグのmt:Loopで出力

コンテンツフィールドをマルチフィールドにしたフィールドを json_decode して変数に格納します。

<mt:SetVarBlock name="multifield"
  ><mt:ContentField content_field="マルチフィールド"
    ><mt:ContentFieldValue /></mt:ContentField
></mt:SetVarBlock>
<mt:Var name="multifield" convert_breaks="0" json_decode="1" setvar="json" />
<mt:Var name="json" key="items" setvar="items" />

json_decode で格納した変数を mt:Loop で取り出します。
どのようなJSONが確認するには、マルチフィールドにある「保存データを表示」で参照することが出来ます。

保存データを表示

mt:Loop でマルチフィールドの取り出しは以下のようになります。
深いJSONの値を取得するために都度 mt:Loop で潜る必要があります。
とくに複雑な書き方になるのは連続するフィールド(テーブル)や様々なフィールドをグループ化するフィールド(マルチカラムコンテンツ)ループを入れ子にしなければならないフィールドはテーブルやマルチカラムコンテンツになります。
mt:Loop で取り出す場合は、かなり表示側のテンプレが長くなってしまう問題があります。
今回のサンプルでは紹介しませんが、 SetVarTemplate を駆使してコンポーネント化するような設計が良いかと思います。

  • mt:Loopでitemsを回す
  • mt:Ifでtypeやlabelの条件を設定
  • マッチした値を出力
  • 深いJSONの値はさらにmt:Loopで回す
<mt:Var name="json" key="items" setvar="items" />
<mt:SetVar name="items_index" value="0" />
<mt:Loop name="items">
  <mt:Var name="items" index="$items_index" setvar="item" />
  <mt:Ignore>見出しレベル</mt:Ignore>
  <mt:If name="item" key="type" eq="h1">
  <h1 class="uk-heading-bullet"><mt:Var name="item" key="data" /></h1>
  </mt:If>
  <mt:If name="item" key="type" eq="h2">
  <h2 class="uk-heading-line"><mt:Var name="item" key="data" /></h2>
  </mt:If>
  <mt:If name="item" key="type" eq="h3">
  <h3 class="uk-heading-divider"><mt:Var name="item" key="data" /></h3>
  </mt:If>
  <mt:Ignore>テキストレベル</mt:Ignore>
  <mt:If name="item" key="type" eq="text">
  <p><mt:Var name="item" key="data" /></p>
  </mt:If>
  <mt:If name="item" key="type" eq="textarea">
  <p><mt:Var name="item" key="data" remove_html="1" convert_breaks="0" nl2br="1" /></p>
  </mt:If>
  <mt:Ignore>画像アップロード</mt:Ignore>
  <mt:If name="item" key="type" eq="image">
  <div class="uk-margin-auto uk-margin-auto-vertical uk-width-1-2@s uk-card uk-card-default uk-card-body">
    <img src="<mt:Var name="item" key="url" />">
  </div>
  </mt:If>
  <mt:Ignore>テーブル</mt:Ignore>
  <mt:If name="item" key="type" eq="table">
  <mt:Var name="item" key="data" setvar="_data" />
  <mt:Ignore>表組み</mt:Ignore>
  <mt:If name="item" key="label" eq="表組み">
    <mt:SetVar name="items_index2" value="0" />
    <mt:Loop name="_data">
    <mt:Var name="_data" index="$items_index2" setvar="__data" />
    <mt:SetVar name="items_index3" value="0" />
    <mt:If name="__first__"><table class="uk-table uk-table-hover uk-table-divider"></mt:If>
    <mt:Loop name="__data">
      <mt:Var name="__data" index="$items_index3" setvar="___data" />
      <mt:If name="___data" key="label" eq="見出し"><mt:Var name="___data" key="data" setvar="__title" /></mt:If>
      <mt:If name="___data" key="label" eq="テキスト"><mt:Var name="___data" key="data" setvar="__text" /></mt:If>
      <mt:SetVar name="items_index3" op="++" />
    </mt:Loop>
    <tr>
      <mt:If name="__title"><th><mt:Var name="__title" /></th></mt:If>
      <mt:If name="__text"><td><mt:Var name="__text" /></td></mt:If>
    </tr>
    <mt:If name="__last__"></table></mt:If>
    <mt:SetVar name="items_index2" op="++" />
    </mt:Loop>
  </mt:If>
  <mt:Ignore>リスト</mt:Ignore>
  <mt:If name="item" key="label" eq="リスト">
  <mt:SetVar name="items_index2" value="0" />
  <mt:Loop name="_data">
    <mt:Var name="_data" index="$items_index2" setvar="__data" />
    <mt:SetVar name="items_index3" value="0" />
    <mt:If name="__first__"><ul class="uk-list uk-list-bullet"></mt:If>
    <mt:Loop name="__data">
    <mt:Var name="__data" index="$items_index3" setvar="___data" />
      <mt:If name="___data" key="label" eq="テキスト"><mt:Var name="___data" key="data" setvar="__text" /></mt:If>
      <mt:If name="___data" key="label" eq="URL"><mt:Var name="___data" key="data" setvar="__url" /></mt:If>
    <mt:SetVar name="items_index3" op="++" />
    </mt:Loop>
    <mt:If name="__text"><li><mt:If name="__url"><a href="<mt:Var name='__url' />" target="_blank" target="_blank"></mt:If><mt:Var name="__text" /></li><mt:If name="__url"></a></mt:If></mt:If>
  <mt:If name="__last__"></ul></mt:If>
  <mt:SetVar name="items_index2" op="++" />
  </mt:Loop>
  </mt:If>
  </mt:If>
  <mt:Ignore>マルチカラムコンテンツ</mt:Ignore>
  <mt:If name="item" key="type" eq="multi-column-content">
  <mt:Var name="item" key="data" setvar="_data" />
  <mt:Ignore>画像単体アップロード + テキスト</mt:Ignore>
  <mt:If name="item" key="label" eq="画像単体アップロード + テキスト">
    <mt:SetVar name="items_index2" value="0" />
    <mt:Loop name="_data">
    <mt:Var name="_data" index="$items_index2" setvar="__data" />
    <mt:SetVar name="items_index3" value="0" />
    <mt:Loop name="__data">
      <mt:Var name="__data" index="$items_index3" setvar="___data" />
      <mt:If name="___data" key="label" eq="画像"><mt:Var name="___data" key="url" setvar="img_url" /></mt:If>
      <mt:If name="___data" key="label" eq="キャプション"><mt:Var name="___data" key="data" setvar="img_text" /></mt:If>
      <mt:SetVar name="items_index3" op="++" />
    </mt:Loop>
    <mt:SetVar name="items_index2" op="++" />
    </mt:Loop>
    <mt:If name="img_url">
    <div class="uk-flex-middle" uk-grid>
    <div class="uk-width-2-3@m">
      <p><mt:Var name="img_text" /></p>
    </div>
    <div class="uk-width-1-3@m uk-flex-first">
      <img src="<mt:Var name='img_url' />">
    </div>
    </div>
    </mt:If>
  </mt:If>
  </mt:If>
  <mt:SetVar name="items_index" op="++" />
</mt:Loop>

例)v2.3.0から実装されたmt:Foreach、mt:NestVarタグで出力

v2.3.0から実装されたタグ mt:Foreachmt:NestVar を使うことで単純にインクリメントせずにループが可能になり且つ深いJSONを取り出すのをループを繰り返しせずにドットで取り出すことが可能になりました。
mt:Loop と同じようにように設定した取り出し方の書いた例になります。
連続したフィールド(テーブル系)やマルチカラムコンテンツの値は mt:Loop の取り出し方に比べるとわかりやすくなったと思います。

  • mt:Foreachでmt:Loopのようなインクリメントせずにループが可能
  • mt:NestVarでmt:Loopのような入れ子せずにドットで取得が可能

複雑なことをするとテンプレで行うロジックの見通しが悪くなり、デバッグや改修し辛いコードになると思います。
mt:Foreachmt:NestVar はテンプレ実装側としては嬉しいタグになります。(マルチフィールド以外でも利用できますし)

<mt:Foreach name="items" as="item">
  <mt:Ignore>見出しレベル</mt:Ignore>
  <mt:If name="item" key="type" eq="h1">
  <h1 class="uk-heading-bullet"><mt:Var name="item" key="data" /></h1>
  </mt:If>
  <mt:If name="item" key="type" eq="h2">
  <h2 class="uk-heading-line"><mt:Var name="item" key="data" /></h2>
  </mt:If>
  <mt:If name="item" key="type" eq="h3">
  <h3 class="uk-heading-divider"><mt:Var name="item" key="data" /></h3>
  </mt:If>
  <mt:Ignore>テキストレベル</mt:Ignore>
  <mt:If name="item" key="type" eq="text">
  <p class="uk-text-small"><mt:Var name="item" key="data" /></p>
  </mt:If>
  <mt:If name="item" key="type" eq="textarea">
  <p class="uk-text-small"><mt:Var name="item" key="data" remove_html="1" convert_breaks="0" nl2br="1" /></p>
  </mt:If>
  <mt:Ignore>画像アップロード</mt:Ignore>
  <mt:If name="item" key="type" eq="image">
  <div class="uk-margin-auto uk-margin-auto-vertical uk-width-1-2@s uk-card uk-card-default uk-card-body">
    <img src="<mt:Var name="item" key="url" />">
  </div>
  </mt:If>
  <mt:Ignore>テーブル</mt:Ignore>
  <mt:If name="item" key="type" eq="table">
  <mt:Ignore>表組み</mt:Ignore>
  <mt:If name="item" key="label" eq="表組み">
    <mt:Foreach name="item.data" as="_data">
    <mt:If name="__first__"><table class="uk-table uk-table-hover uk-table-divider"></mt:If>
    <tr>
      <th><mt:NestVar name="_data.0.data" /></th>
      <td><mt:NestVar name="_data.1.data" /></td>
    </tr>
    <mt:If name="__last__"></table></mt:If>
    </mt:Foreach>
  </mt:If>
  <mt:Ignore>リスト</mt:Ignore>
  <mt:If name="item" key="label" eq="リスト">
    <mt:Foreach name="item.data" as="_data">
    <mt:If name="__first__"><ul class="uk-list uk-list-bullet"></mt:If>
    <li><a href="<mt:NestVar name='_data.0.data' />"><mt:NestVar name="_data.1.data" /></a></li>
    <mt:If name="__last__"></ul></mt:If>
    </mt:Foreach>
  </mt:If>
  </mt:If>
  <mt:Ignore>マルチカラムコンテンツ</mt:Ignore>
  <mt:If name="item" key="type" eq="multi-column-content">
  <mt:Ignore>画像単体アップロード + テキスト</mt:Ignore>
  <mt:If name="item" key="label" eq="画像単体アップロード + テキスト">

    <mt:Foreach name="item.data" as="_data">
    <mt:Ignore>テキストデータの初期化</mt:Ignore>
    <mt:SetVar name="_text" />
    <mt:If name="__first__">
    <div class="uk-flex-middle" uk-grid>
    </mt:If>
      <mt:NestVar name="_data.0.type" setvar="_type" />
      <mt:If name="_type" eq="text">
      <mt:NestVar name="_data.0.data" setvar="_text" />
      </mt:If>
      <mt:NestVar name='_data.0.url' setvar="_url" />

      <mt:If name="_text">
      <div class="uk-width-2-3@m">
      <p><mt:Var name="_text" /></p>
      </div>
      </mt:If>

      <mt:If name="_url">
      <div class="uk-width-1-3@m uk-flex-first">
      <img src="<mt:NestVar name='_data.0.url' />">
      </div>
      </mt:If>

    <mt:If name="__last__">
    </div>
    </mt:If>
    </mt:Foreach>

  </mt:If>
  </mt:If>
</mt:Foreach>

最終コードはこちら

最終的に出来たコードをGistに書いておきましたので、取り出しの参考になればと思います。

マルチフィールドでmt:Loopとmt:Foreach、mt:NestVarタグを使った簡単な例を交えた紹介になります。
これから導入する方はぜひ参考にしてみてください。
明日は取得したマルチフィールドをVue.jsで出力するTipsを紹介したいと思います。

<ClientOnly>
<PostAdSense />
</ClientOnly>