MovableType

クラス構文型で管理できるMTテンプレートの書き方

この記事は「MovableType Advent Calendar 2022」の記事です。

混沌としたMTテンプレート

職務がら多くの人の手を経た MovableType のテンプレートをよく見て、以下のようなことを思っていました。

  • モジュールやテンプレートの管理思想がバラバラ!
  • MTSetVarTemplate タグや MTSetVarBlock タグの内容がどこで宣言されているかわからない!
  • MTタグの出力範囲とHTMLタグ範囲が分離されていないので、テンプレートが冗長に!
  • 変数の命名規則がバラバラ! キャメルケースやスネークケース、日本語だったり英語だったり!!

よく考えてみると、MTタグってプログラミング言語のように、そもそも管理方法のルール自体がないのかなと思います。

書き方が多種多様なのは良いことですが、ルールなしの状態は管理や実装が属人的になり継続的な支援に向いていません。

ご紹介する「クラス構文型」テンプレートは、この問題を解消するために設計しました。上記の課題が解消できれば、実装やサイト運用はもっとスムーズになると思います。

実装したエンジニアが退職したからと「現状把握の調査」が作業工数に含まれていたりしないでしょうか?

もっと発注者も受注者も幸せになる方法があると思うのです。

クラス構文型テンプレート

記述ルール

  • MTSetVarTemplate タグの命名は CSS 設計規則の「BEM」で命名を行うこと。
  • クラスは MTSetVarTemplate タグをネストさせて作成すること。
  • クラス内の変数は必ず初期化すること。
  • クラス変数名の接頭語には「class」を追加すること。
  • タグでHTMLを出力する際は、接頭語に「--output」を追加すること。
  • MTSetVarTemplate タグは「note」でコメントを残すこと。

BEMのように命名を行う

BEMとは

厳格な命名ルールが特徴的なCSS設計規則のひとつ。「Block」「Element「Modifier」の3つの概念で命名を行います。

  • Block: 管理単位。検索エリアやニュースエリアなどの大きな要素で定義する。
  • Element: パーツ単位。Block の中でのみ使用するパーツを定義する。検索エリアの入力蘭など。
  • Modifier: 装飾単位。Block や Element に追加する装飾内容を定義する。ニュースエリアで選択中のタブなど。

複数単語になる場合は、ハイフン1つで区切ります。

クラス名の宣言

「Block」「Element「Modifier」の要領で命名します。

・記述例: サイト単位のクラス

  • Block: サイト: ニュースリリース
  • Element: テンプレート: 記事アーカイブ
  • Modifier: テンプレート名: entry

関数名は「class-news__archive-entry--entry」になります。

・記述例: 機能単位のクラス

  • Block: ヘルパー
  • Element: ページャー(機能名)
  • Modifier: なし

関数名は「class-helper__pager」になります。

・記述例: 複雑な処理

  • Block: サイト: ニュースリリース
  • Element: テンプレート: 記事アーカイブ
  • Modifier: テンプレート名: entry
  • Modifier: カスタムナビ(機能名)
  • Modifier: ハッシュ(動作名)

関数名は「class-news__archive-entry--entry--custom-navi--hash」になります。

実装方法

システム: テンプレートモジュール(class_template)

<mt:SetVarTemplate name="class-news" note="ニュースリリース">
  <mt:SetVarTemplate name="class-news__archive-etnry--entry" note="記事ページ">

    <mt:SetVarTemplate name="class-news__archive-etnry--entry--init--output" note="最初に変数を定義">
      何かあれば記述する。
    </mt:SetVarTemplate>

    <mt:SetVarTemplate name="class-news__archive-etnry--entry--entryprev--output" note="前の記事を表示する">
      <mt:EntryPrevious>
        <li><a href="<mt:EntryPermalink>"><mt:EntryTitle></a></li>
      </mt:EntryPrevious>
    </mt:SetVarTemplate>

    <mt:SetVarTemplate name="class-news__archive-etnry--entry--entrynext--output" note="次の記事を表示する">
      <mt:EntryNext>
        <li><a href="<mt:EntryPermalink>"><mt:EntryTitle></a></li>
      </mt:EntryNext>
    </mt:SetVarTemplate>

    <mt:SetVarTemplate name="class-news__archive-etnry--entry--custom-navi" note="複雑なナビゲーション">
      ハッシュ配列を作成するなど
      <mt:SetVarTemplate name="class-news__archive-etnry--entry--custom-navi--output" note="複雑なルールで記事を表示する">
        ハッシュ配列をMTLoop タグで出力するなど。
      </mt:SetVarTemplate>
    </mt:SetVarTemplate>

    <mt:SetVarTemplate name="class-news__archive-etnry--entry--custom-navi-hard" note="さらに複雑なナビゲーション">
      <mt:SetVarTemplate name="class-news__archive-etnry--entry--custom-navi-hard--entry" note="複雑な処理">
        複雑な処理
      </mt:SetVarTemplate>
      <mt:SetVarTemplate name="class-news__archive-etnry--entry--custom-navi-hard--category" note="複雑な処理">
        複雑な処理
      </mt:SetVarTemplate>
      <mt:SetVarTemplate name="class-news__archive-etnry--entry--custom-navi-hard--output" note="複雑なルールで記事を表示する">
        <mt:Var name="class-news__archive-etnry--entry--custom-navi-hard--entry">
        <mt:Var name="class-news__archive-etnry--entry--custom-navi-hard--category">
        ハッシュ配列をMTLoop タグで出力するなど。
      </mt:SetVarTemplate>
    </mt:SetVarTemplate>

    <mt:SetVarTemplate name="class-news__archive-etnry--entry--output" note="出力">
      <mt:var name="class-news__archive-etnry--entry--init--output">
      <mt:var name="class-news__archive-etnry--entry--custom-navi">
      <mt:var name="class-news__archive-etnry--entry--custom-navi-hard">
      <!DOCTYPE html>
      <html>
        <head>省略</head>
        <body>
          <h1><mt:EntryTitle></h1>
          <div><mt:EntryBody></div>
          <mt:Var name="class-news__archive-etnry--entry--entryprev--output">
          <mt:Var name="class-news__archive-etnry--entry--entrynext--output">
          <mt:var name="class-news__archive-etnry--entry--custom-navi--output">
          <mt:var name="class-news__archive-etnry--entry--custom-navi-hard--output">
        </body>
      </html>
    </mt:SetVarTemplate>
  </mt:SetVarTemplate>
</mt:SetVarTemplate>

ニュースリリースサイト: 記事アーカイブテンプレート(entry)

<>
<mt:Include module="class_template" global="1" note="上記のテンプレート">
<mt:Var name="class-news">
<mt:Var name="class-news__archive-etnry--entry">
<mt:Var name="class-news__archive-etnry--entry--output">

利点

サイト配下にどのような処理があるかの把握が容易

以下のニュースリリースサイトには、5つのテンプレートとその用途がわかるようになっています。

「class-news__custom-index--search-json」は「検索用JSON」のテンプレートといった具合です。

「class-news__module」はテンプレートモジュールに記述していた内容を「クラス構文」で定義します。さようならテンプレートモジュール。

<mt:SetVarTemplate name="class-news" note="ニュースリリース">
  <mt:SetVarTemplate name="class-news__module" note="モジュール">
    <mt:SetVarTemplate name="class-news__module--sidenavi" note="一覧と記事ページの右ナビ">省略</mt:SetVarTemplate>
  </mt:SetVarTemplate>
  <mt:SetVarTemplate name="class-news__main-index--index" note="一覧ページ"></mt:SetVarTemplate>
  <mt:SetVarTemplate name="class-news__custom-index--home-include" note="サイトホームインクルード用">省略</mt:SetVarTemplate>
  <mt:SetVarTemplate name="class-news__custom-index--search-json" note="検索用JSON">省略</mt:SetVarTemplate>
  <mt:SetVarTemplate name="class-news__archive-etnry--entry" note="記事ページ">省略</mt:SetVarTemplate>
</mt:SetVarTemplate>

1ファイルで全てのサイトの処理部分が管理可能

もちろんサイトごとに分けても良いです。

<mt:SetVarTemplate name="class-helper" note="ヘルパー">省略</mt:SetVarTemplate>
<mt:SetVarTemplate name="class-template" note="テンプレートクラスごとの定義">省略</mt:SetVarTemplate>
<mt:SetVarTemplate name="class-news" note="ニュースリリース">省略</mt:SetVarTemplate>
<mt:SetVarTemplate name="class-ir" note="IR情報">省略</mt:SetVarTemplate>
<mt:SetVarTemplate name="class-csr" note="CSR情報">省略</mt:SetVarTemplate>

Git管理

テンプレートモジュール(class_template)の「ファイルリンク先」のファイルを管理するだけで、全てのサイトの処理部分が管理可能です。

チーム開発でテンプレート進捗状況が分かりやすくなります。

テンプレートの半自動デプロイ

GitHubにコミットして、テンプレートの自動デプロイができます。フィールドは先に手動で追加したり、手動で再構築は必要ですが...

欠点

  • クラス構文型と銘打っているが、変数のスコープはグローバルのまま。
  • ローカル変数がないので、値の初期化に注意が必要。

あとがき

テンプレートモジュールに役割を持たせ管理するのには限界があるように感じています。

きれいに設計できて、ドキュメントを整備しても、たくさんの人の手を介したり時間が経過すると、必ず情報の劣化が発生します。

情報が抜けたり、変わったり、情報自体が消えたり、例外が正しい情報として伝わったり。

自分だけでなく引き継ぐ人のためにも、ルールがあればある程度は制御することができるように思います。

発注者も受注者もお幸せに! 良いお年を!

混沌とした開発現場のはなしはこちら。管理画面のカスタマイズが可能なプラグイン「MyAdminStyle」のご紹介 良いお年を!