mtapp.columnGroup に任意のフィールドやテキストを表示するだけのフィールドを入れる方法

2026-02-17
12分で読了
更新: 2026-02-17

目次

Movable Type のコンテンツデータ編集画面で mtapp.columnGroup を使うと、フィールドをグループ化してカード形式やアコーディオン形式で段組レイアウトにできます。とても便利な機能なのですが、ちょっとしたハマりポイントがあります。

テキスト表示フィールドや、自分で作った任意のフィールドが columnGroup の中に入ってくれない――という問題です。

今回はこの原因と回避テクニックをご紹介します。

なぜテキスト表示フィールドは columnGroup に入らないのか

mtapp.columnGroup は内部で window.mtappVars.contentDataFields というオブジェクトを参照して、各フィールドの DOM 要素を取得しています。

const contentField = window.mtappVars.contentDataFields['contentField' + field.id];

この contentDataFields は、MTAppjQuery の初期化時に getContentDataFields() という関数で自動的に構築されます。具体的には、#content_data > div の中に name="content-field-XX"id="asset-field-XX" といった特定のパターンを持つ要素があるかどうかでフィールドを識別しています。

ところが、テキスト表示フィールドの HTML はこうなっています。

<div class="mb-3">
    <div class="first-child">テキスト表示エリアのテキストです。</div>
    <small class="form-text text-muted last-child"></small>
</div>

通常のフィールドと違って id がなく、 data-mtapp-field-* 属性も付かず、内部に name="content-field-XX" のような要素もありません。そのため getContentDataFields() の検出対象外となり、contentDataFields に登録されません。

登録されていないフィールドは columnGroup から見えないので、グループの中に入れようとしても無視されてしまうわけです。

解決策: columnGroup 実行前に手動で登録する

columnGroup を呼び出す前に、任意のフィールドを contentDataFields へ手動登録するという方法で対処できます。

やることは 3 つです。

  1. mtapp.makeField でフィールドの HTML を作って DOM に挿入する
  2. 挿入した要素に contentFieldXXX 形式の id を付与する
  3. window.mtappVars.contentDataFields へ登録する

この 3 ステップをまとめたヘルパー関数を作っておくと、1 つでも複数でも同じ書き方で追加できて便利です。

ヘルパー関数を用意する

/**
 * 任意のフィールドを作成して contentDataFields に登録する
 * @param {Object} params
 * @param {number} params.id - 他と衝突しない任意の数値 ID
 * @param {string} params.label - フィールドのラベル
 * @param {string} params.content - フィールド本文の HTML
 * @param {string} [params.hint] - 補足ヒント(省略可)
 * @param {string} params.anchorSelector - 挿入基準となる既存フィールドのセレクタ
 */
function registerCustomField({ id, label, content, hint = '', anchorSelector }) {
    // mtapp.makeField(type: 'cd') で HTML 文字列を生成
    const html = mtapp.makeField({
        basename: `contentField${id}`,
        label,
        content,
        hint,
        type: 'cd'
    });

    const anchor = document.querySelector(anchorSelector);
    const selector = `#contentField${id}`;

    // 重複挿入を防止しつつ DOM に追加
    if (anchor && !document.querySelector(selector)) {
        anchor.insertAdjacentHTML('afterend', html);
        // mtapp.makeField(type: 'cd') はルート要素に id を付けないため手動で付与
        const inserted = anchor.nextElementSibling;
        if (inserted) {
            inserted.id = `contentField${id}`;
        }
    }

    // columnGroup が参照する辞書へ登録
    const element = document.querySelector(selector);
    if (element) {
        window.mtappVars.contentDataFields[`contentField${id}`] = element;
    }
}

ポイントは 2 つあります。

  • mtapp.makeField({ type: 'cd' }) はルート要素に id を付与しないため、挿入後に insertedElement.id で手動セットしています
  • columnGroupcontentDataFields['contentFieldXXX'] でフィールドを引くので、この辞書への登録が必須です

使い方

1 つだけ追加する場合

const anchorSelector = '#contentField' + mtapp.getContentFieldIdByLabel('基準にするフィールド名');

registerCustomField({
    id: 999001,
    label: '補足説明テキスト',
    content: '<div class="first-child">ここに表示したいテキストを書きます。</div>',
    hint: '補足のヒントテキストです。',
    anchorSelector
});

mtapp.columnGroup({
    group: [
        {
            label: 'フィールドグループ',
            key: 'my-group',
            fields: [
                { label: 'テキスト', column: 'col-lg-6' },
                { id: 999001, label: '補足説明テキスト', column: 'col-lg-6' }
            ]
        }
    ],
    selector: anchorSelector,
    type: 'card',
    method: 'after'
});

複数追加する場合

registerCustomField を追加したいフィールドの数だけ呼ぶだけです。

const anchorSelector = '#contentField' + mtapp.getContentFieldIdByLabel('基準にするフィールド名');

registerCustomField({
    id: 999001,
    label: '注意事項',
    content: '<div class="first-child">この商品は受注生産です。</div>',
    anchorSelector
});

registerCustomField({
    id: 999002,
    label: '配送について',
    content: '<div class="first-child">通常 3〜5 営業日で発送します。</div>',
    anchorSelector
});

mtapp.columnGroup({
    group: [
        {
            label: '補足情報',
            key: 'supplementary',
            fields: [
                { label: 'テキスト', column: 'col-lg-6' },
                { id: 999001, label: '注意事項', column: 'col-lg-6' },
                { id: 999002, label: '配送について', column: 'col-lg-6' }
            ]
        }
    ],
    selector: anchorSelector,
    type: 'card',
    method: 'after'
});

通常のフィールドは label だけで指定できますが、手動登録したフィールドは contentType.fields に存在しないため label からの ID 逆引きができません。id を明示的に渡す必要がある点だけ注意してください。

ちなみに、columnGroup の内部では field.id が渡されている場合、field.label は一切参照されません。label から ID を逆引きするのは id が未指定のときだけです。なので、id を指定する場合の label は省略しても動作しますが、コードの可読性のために書いておくのがおすすめです。

この方法の良いところ

  • user.js だけで完結します
  • ヘルパー関数を 1 つ用意しておけば、追加したいフィールドの数だけ呼ぶだけで済みます
  • テキスト表示フィールドに限らず、任意の HTML をフィールドとして columnGroup に組み込めます

まとめ

mtapp.columnGroup にテキスト表示フィールドや自作フィールドが入らない原因は、window.mtappVars.contentDataFields に登録されていないことでした。

columnGroup 実行前に以下の 3 つを行えば解決します。

  1. mtapp.makeField で HTML を生成して DOM に挿入
  2. 挿入した要素に contentFieldXXX 形式の id を付与
  3. window.mtappVars.contentDataFields へ手動登録

この 3 ステップをヘルパー関数にまとめておけば、1 つでも複数でも同じ書き方で追加できます。コンテンツデータ編集画面のレイアウトを細かくカスタマイズしたいときに、ぜひ試してみてください。

この記事をシェア

関連記事