a-blog cmsのテーマ変更を簡単にする js-theme_loader & 定義ファイル

a-blog cmsのテーマの変更を簡単にする



a-blog cmsのテーマファイルは、テキストでテーマディレクトリ名を入力して設定します。さらに、テーマごとにトップページ、一覧ページ、詳細ページで使われるテンプレートファイルは異なるので、それらも必要に応じて入力する必要があります。

打ちっ放しのコンクリート的実装

テキストベースは、安心感も安定感もあるのですが、どうにもヒンヤリした感触のインターフェースです。今回はその辺りも、もう少しだけユーザーフレンドリーにしてみたいと思います。

UIの改善以外の問題意識として、a-blog cmsを触って間もないユーザーが陥りがちな、テンプレートの不整合による404問題があります。これは、plainからcompany3へ変更したとき、あるいはcompany1からvicunaへ変更したときなど、テーマを変更したときに、自動ではテンプレートファイルの設定が追従しないことによるものです。

今回は、それもテーマにテンプレートの初期セットを記録する定義ファイルという実装を加えることで、自動化してテーマの切り替えが安全確実なものになるようにチャレンジ。

  • テーマをセレクトボックスで選べるようにする(themes内の自動探索)
  • テーマの初期テンプレートをjsonで定義する
  • テーマの初期セットを定義ファイルから読み込めるようにする

以下、今回の作業内容。

テーマの変更をセレクトボックスから選べるようにする

/themes/system/admin/config/theme.html の 13行目付近

下記のように編集してください。Admin_Dashboard_ThemeChangerは、見慣れないモジュールですが、初期バージョンから搭載(だけ)されている埋もれモジュールなので、テンプレートに書くだけで動作します。select要素の次に、例ではspanで置いてある、#js-theme_loader-progressも記述してください。これが無いと後述のスクリプトが通信中かどうか分かりません。

<form action="" method="post">
     <h3>テーマ</h3>
     <table class="adminTable adminTableY">
          <tr>
               <th>テーマ ディレクトリ名<img src="/images/tooltip.gif" alt="ヘルプ" width="12" height="12" id="tooltip-theme" class="tooltipIcon" /></th>
               <td><!-- BEGIN_MODULE Admin_Dashboard_ThemeChanger -->
                    <select name="theme" id="js-theme_loader"><!-- BEGIN theme:loop -->
                         <option value="{theme}"{selected}>{label}</option><!-- END theme:loop -->
                    </select><!-- END_MODULE Admin_Dashboard_ThemeChanger -->
                    <span id="js-theme_lodader-progress"></span>
                    <input type="hidden" name="config[]" value="theme" />
                    <input type="hidden" name="theme:validator#required" id="validator-theme-required" />
                    <label for="validator-theme-required" class="validator-result-{theme:validator#required}">テーマが指定されていません。</label>
               </td>
          </tr>
     </table>

テーマの初期テンプレートをjsonで定義する

各テーマディレクトリ内の直下に、テーマ名.jsonで保存します。

plan テーマの場合
/themes/plain/plain.json

中身はこんな感じで。今のところ生々しいjsonです。

// plainの場合はこんな
{
"tpl_top"         : "index.html",
"tpl_index"       : "index.html",
"tpl_detail"      : "index.html",
"tpl_404"         : "404.html",
"tpl_admin"       : "admin.html",
"tpl_entry_edit"  : "index.html",
"tpl_entry_add"   : "index.html",
"login_tpl"       : "login.html"
}

// company3の場合はこんな
{
"tpl_top"         : "top.html",
"tpl_index"       : "index.html",
"tpl_detail"      : "entry.html",
"tpl_404"         : "404.html",
"tpl_admin"       : "admin.html",
"tpl_entry_edit"  : "entry.html",
"tpl_entry_add"   : "entry.html",
"login_tpl"       : "login.html"
}

テーマの初期セットを定義ファイルから読み込めるようにする

管理ページ中のテーマ設定のテンプレート、先ほどと同じく/themes/system/admin/config/theme.htmlの一番上あたりで良いので、以下のスクリプトを、script要素としてコピペします。

$(function()
{
    $('#js-theme_loader').change(function()
    {
        var $label  = $('#js-theme_loader-progress');
        var loading = setInterval(function(){
            var str     = 'loading';
            var now     = $label.text();
            var cnt     = $label.text().length - str.length;

            if ( now == '' | cnt == 3 ) {
                $label.text(str + '.');
            } else {
                $label.text(now + '.');
            }
        }, 500);

        var theme   = $(this).val();
        $.ajax({
            url     : '/themes/' + theme + '/' + theme + '.json',
            type    : 'GET',
            dataType: 'json',
            cache   : false,
            success : function(json)
            {
                clearInterval(loading);
                $label.text('success!');
                $('input[name="tpl_top"]').val(json.tpl_top);
                $('input[name="tpl_index"]').val(json.tpl_index);
                $('input[name="tpl_detail"]').val(json.tpl_detail);
                $('input[name="tpl_404"]').val(json.tpl_404);
                $('input[name="tpl_admin"]').val(json.tpl_admin);
                $('input[name="tpl_entry_edit"]').val(json.tpl_entry_edit);
                $('input[name="tpl_entry_add"]').val(json.tpl_entry_add);
                $('input[name="tpl_login"]').val(json.tpl_login);
            },
            error   : function(xhr, status)
            {
                clearInterval(loading);
                $label.text('fail ( ' +xhr.status+' )');
            }
        });
    });
});

これでjsonから読み込み&反映されるはず

これで、セレクトボックスからテーマ名を選択すると定義ファイルの読み込みが試行されます。定義ファイルが見つかれば、successの表示と共に、定義ファイル通りに各テンプレートのinput要素内が書き換わります。

定義ファイルが見つからなければfailが表示されて、何も起きません。

まじめに実装する場合の展望

今回はクライアント側(jQuery)だけで、どうとでもなる範囲で実装してみました。以下、まじめに実装する場合の展望とか問題点。

  • JSONは比較的容易なフォーマットだが、不慣れな場合に構文エラーでハマりやすい
  • /themes/your_theme/your_theme.json に直接アクセスしてしまっている
  • a-blog cmsのセッション周りの挙動を考慮し、本当はPHPを介してデータを返す必要がある
  • どうせPHPを介す必要があるならば、YAMLのほうが読み書きしやすいかも
  • ルールとかで適用されているテンプレート設定は、さすがにどうしようもないかも