スタッフブログ Staff Blog

PowerCMSのスニペット・フィールドで種類の異なるカスタムフィールドをまとめる

通常 Movable Type で種類(テキスト・複数行テキスト・アイテム・画像など)の異なるカスタムフィールドを作成する際は別々のフィールドとして作成する事になりますが、別々のカスタムフィールドとして作成する場合は以下のような問題があります。

  • フィールド数が多くなると編集画面が縦長になる
  • フィールド数が多く、また記事数も増えた時に保存/再構築処理が重くなる

これらの問題を解決する一つの方法として PowerCMS のスニペット・フィールドでまとめる方法をご紹介します。

スニペット・フィールドを作成する

今回は以下のフィールドを持ったスニペット・フィールドを作成します。

  • タイトル(テキスト)
  • 概要(複数行テキスト)
  • サムネイル(画像)

  • システムオブジェクト: ブログ記事
  • 種類: スニペット
  • オプション: title,summary,customfield_thumb
  • 規定値: 後述します
  • ベースネーム: entry_snippet01
  • テンプレートタグ: EntrySnippet01

ここでは上記のように入力してスニペット・フィールドを保存します。 オプション欄はテンプレートタグでスニペット・フィールドの値を取り出す際のキーとして利用しますが、画像フィールドは Movable Type のアイテム選択ダイアログを流用するため必ず「customfield_」で始まる必要があります。

規定値にスニペット・フィールドのテンプレートを入力する

一度スニペット・フィールドを保存すると規定値が入力可能になりますので以下のように入力します。

<mt:Ignore>アイテム・画像を表示するためのテンプレート</mt:Ignore>
<mt:SetVarTemplate name="tmpl_file_field">
    <mt:SetVarBlock name="_name">customfield_<$mt:Var name="_key"$></mt:SetVarBlock>
    <mt:SetVarBlock name="__at"><$mt:Var name="asset_type" _default="image"$></mt:SetVarBlock>
    <mt:SetVarBlock name="__atl"><$mt:Var name="asset_type_label" _default="ファイル"$></mt:SetVarBlock>
    <mt:SetVarBlock name="__w"><$mt:Var name="thumbnail_width" _default="150"$></mt:SetVarBlock>
    <mt:SetVarBlock name="__h"><$mt:Var name="thumbnail_height" _default="150"$></mt:SetVarBlock>

    <mt:SetVarBlock name="_"><$mt:Var name="_name"$>_original</mt:SetVarBlock>
    <mt:SetVarBlock name="asset_id"><$mt:Var name="$_" regex_replace='/\A(?:__snippet_upload_asset__(\d+)\z|.*)/','$1'$></mt:SetVarBlock>
    <input type="hidden" name="<$mt:Var name="_" escape="html"$>" value="<$mt:Var name="$_" escape="html"$>">

    <$mt:SetVar name="_cf_preview_html" value=""$>
    <mt:If name="asset_id" like='/\A[1-9]\d*\z/'>
        <mt:Asset id="$asset_id" setvar="_cf_preview_html">
            <mt:If tag="AssetMIMEType" like="/\A(?:image\/|\z)/">
                <a href="<$mt:AssetURL$>" target="_blank" title="<$mt:Trans phrase="View image" escape="html"$>"><img src="<$mt:AssetThumbnailURL height="$__h" width="$__w"$>" alt=""></a>
            <mt:Else>
                <a href="<$mt:AssetURL$>" target="_blank"><$mt:AssetFileName escape="html"$></a>
            </mt:If>
        </mt:Asset>
    <mt:Else>
        <$mt:Var name="$_name"$>
    </mt:If>
    <mt:Unless name="_cf_preview_html" like="/\S/">
        <$mt:SetVar name="asset_id" value=""$>
    </mt:Unless>

    <input type="hidden" name="<$mt:Var name="_name"$>" id="<$mt:Var name="_name"$>" data-asset-chooser="true" value="<$mt:Var name="$_name" escape="html"$>">

    <div id="<$mt:Var name="_name"$>_preview" class="customfield_preview" data-preview-width="<$mt:Var name="__w"$>" data-preview-height="<$mt:Var name="__h"$>">
        <$mt:Var name="_cf_preview_html"$>
    </div>
    <div class="actions-bar" style="clear: none;">
        <div class="actions-bar-inner pkg actions">
            <a href="<$mt:Var name="script_url"$>?__mode=list_asset&_type=asset&blog_id=<$mt:Var name="blog_id"$>&dialog_view=1&filter=class&filter_val=<$mt:Var name="__filter_val"$>&require_type=<$mt:Var name="__filter_val"$>&edit_field=<$mt:Var name="_name"$>&asset_select=1" class="mt-open-dialog">
                <$mt:Var name="__file_label" escape="html"$>を選択
            </a>
            <a href="#" id="<$mt:Var name="_name"$>_remove_asset" class="<mt:Unless name="asset_id">hidden</mt:Unless>" type="submit" onclick="insertCustomFieldAsset('', '<$mt:Var name="_name"$>'); return false;" style="margin-left: 10px;">
                <$mt:Var name="__file_label" escape="html"$>を削除する
            </a>
        </div>
    </div>
    <mt:SetVarBlock name="__selector" append="1"><mt:If name="__selector">, </mt:If>#<$mt:Var name="_name"$>_remove_asset</mt:SetVarBlock>
</mt:SetVarTemplate>

<div id="<$mt:Var name="basename"$>-content">
    <div class="SnippetTable">
        <div class="SnippetTable__row">
            <div class="SnippetTable__title">タイトル</div>
            <div class="SnippetTable__content">
                <mt:SetVarBlock name="_key">title</mt:SetVarBlock>
                <input type="text" name="<$mt:Var name="_key"$>" class="text" value="<$mt:Var name="$_key" escape="html"$>">
            </div>
        </div>
        <div class="SnippetTable__row">
            <div class="SnippetTable__title">概要</div>
            <div class="SnippetTable__content">
                <mt:SetVarBlock name="_key">summary</mt:SetVarBlock>
                <textarea name="<$mt:Var name="_key"$>" class="text medium"><$mt:Var name="$_key" escape="html"$></textarea>
            </div>
        </div>
        <div class="SnippetTable__row">
            <div class="SnippetTable__title">サムネイル</div>
            <div class="SnippetTable__content">
                <mt:SetVarBlock name="_key">thumb</mt:SetVarBlock>
                <$mt:Var name="tmpl_file_field" __file_label="画像" __file_val="image"$>
                <mt:Ignore>アイテムを利用する場合は書きを使用してください。</mt:Ignore>
                <mt:Ignore><$mt:Var name="tmpl_file_field" __file_label="ファイル" __file_val="file"$></mt:Ignore>
            </div>
        </div>
    </div>
</div>

<mt:Ignore>アイテム・画像の選択動作</mt:Ignore>
<mt:If name="__selector">
<script>
    (function($) {
        $(function() {
            $('<$mt:Var name="__selector" escape="js"$>').on("click", function() {
                return insertCustomFieldAsset("", $(this).attr("id").replace(/_remove_asset$/, ""))
            });

            window.insertCustomFieldAsset = function(html, id, preview_html) {
                var $asset = $("#" + id);
                var AssetFieldName = $asset.attr("name");
                var $original = $('input[name="' + AssetFieldName + '_original"]');

                if ($asset.data("asset-chooser")) {
                    var $remove = $('input[name="' + AssetFieldName + '_remove"]');
                    var m = html.match(/^[<]form [m]t:asset-id="(\d+)"[^<]+<a href="([^"]*)/);
                    if (m) {
                        var assetID = m[1];
                        var assetSrc = m[2];
                        $asset.val(assetSrc);
                        $original.val("__snippet_upload_asset__" + assetID);
                        $remove.val("");
                    } else {
                        $asset.val("");
                        $original.val();
                        if ($remove.length > 0) {
                            $remove.val("1");
                        } else {
                            $asset.after($('<input type="hidden" name="' + id + '_remove" value="1">'));
                        }
                    }
                } else {
                    $asset.val(html);
                }
                preview_html = preview_html || html || '';

                var $form = $("<div>" + preview_html + "</div>").find("form:first");
                var $preview = $("#" + id + "_preview");

                if ($form.length !== 1) {
                    var preview_w = $preview.data("preview-width") * 1;
                    var preview_h = $preview.data("preview-height") * 1;
                    var m = preview_html.match(/ src="([^<">]+)/);
                    if (m) {
                        var assetSrc = m[1];
                        var img = new Image();
                        img.src = assetSrc;
                        $(img).on("load", function() {
                            var w = img.width || 0;
                            var h = img.height || 0;
                            if (w >= h) {
                                h = "" + Math.round(h / w * preview_w);
                                w = preview_w;
                            } else {
                                w = "" + Math.round(w / h * preview_h);
                                h = preview_h;
                            }
                            $preview.html(preview_html.replace(/(<img\s(?![^>]*\swidth[\s=])(?![^>]*\sheight[\s=]))/, '$1 width="' + w + '" height="' + h + '"'));
                        });
                    } else {
                        $preview.html(preview_html.replace(/(<img\s(?![^>]*\swidth[\s=])(?![^>]*\sheight[\s=]))/, '$1 width="' + preview_w + '"'));
                    }
                } else {
                    $form.find("a[href]").each(function() {
                        $(this).attr("target", "_blank");
                    });
                    $preview.html($form.html());
                }
                $("#" + id + "_remove_asset")[html ? "removeClass" : "addClass"]("hidden");
                return false;
            };
        });
    }(jQuery));
</script>
</mt:If>

<style>
    .SnippetTable {
        display: table;
        width: 100%;
    }
    .SnippetTable__row {
        display: table-row;
    }
    .SnippetTable__title,
    .SnippetTable__content {
        display: table-cell;
        padding: 10px 0;
        border-bottom: 1px solid #ccc;
        vertical-align: top;
    }
    .SnippetTable__row:first-child .SnippetTable__title,
    .SnippetTable__row:first-child .SnippetTable__content {
        padding-top: 0;
    }
    .SnippetTable__row:last-child .SnippetTable__title,
    .SnippetTable__row:last-child .SnippetTable__content {
        padding-bottom: 0;
        border-bottom: 0;
    }
    .SnippetTable__title {
        padding-right: 10px;
        width: 5em;
        text-align: right;
    }
    .SnippetTable__content .medium {
        height: 7.5em;
    }
</style>

スニペット・フィールドの値を取り出すテンプレートタグ

画像とそれ以外のフィールドで取り出し方が異なります。 画像フィールドはスニペット・フィールドの「テンプレートタグ」として設定したタグ名に「Asset」を繋げたブロックタグと key モディファイアの組み合わせで画像のコンテキストを得ることができます。

画像以外の値の取り出し方

<mt:Ignore>タイトル</mt:Ignore>
<mt:EntrySnippet key="title">

<mt:Ignore>概要</mt:Ignore>
<mt:EntrySnippet key="summary">

画像の値の取り出し方

<mt:Ignore>画像</mt:Ignore>
<mt:EntrySnippetAsset key="customfield_thumb">
    // do something 
</mt:EntrySnippetAsset>

まとめ

PowerCMS のスニペット・フィールドを活用する事で編集画面をすっきりさせる事ができました。 フィールド数が増えた場合はさらに作り込む事で更新しやすいUIを作る事が可能です。

お問い合わせ Contact

制作のご依頼、ご相談などは下記のフォームからご連絡ください。