ナビゲーションモジュールの中でテンプレートを呼び出す方法

ナビゲーションモジュールについては基本的には、管理画面から手動で自由にラベル・リンクを設定し、更新可能にするためのモジュールですが、例えば「採用情報」のコンテンツ以下のエントリーを追加した際に自動で増えるようなメニューに実装したいと思ったことはありませんでしょうか。

Navigation モジュールの設定



採用情報の公開のチェックを外し非表示にします。右側の(追加)ボタンをクリックし、ナビゲーションを 1行追加してください。

ここで、ラベルに acms://bid/1/cid/7/tpl/navi.html と記述します。 こうする事で、ラベルを編集する際に、acms:// で a-blog cms を再度実行し、bid=1 & cid=7の条件テンプレートnavi.html をラベルに編集することになります。

この機能は、1.x から実装されている機能ではありましたが、1回表示する際に a-blog cms をもう一度動作させて結果を取得する という事で、2倍の負荷になる事から、あまり推奨される記述ではありませんでした。推奨されない裏技として封印されてきていました。これを解決するために、テンプレートの部分的書き出し という機能で回避するという手段も用意されています。

しかし、Ver. 2.11.0 からモジュールID のキャッシュ機能ができた事から、本番環境では モジュールID キャッシュ を有効(0分 → 60分) にする事で、60分に1回しか2回動かさないことができるようになりました。

Navigationモジュール のテンプレートを修正

<!-- BEGIN_MODULE Navigation id="nav_global" -->
<nav class="navbar" aria-label="メインメニュー">
@include("/admin/module/setting.html")
<!-- BEGIN navigation:loop -->
	<!-- BEGIN ul#front --><ul><!-- END ul#front -->
		<!-- BEGIN li#front --><li {attr}><!-- END li#front -->
			<!-- BEGIN link#front --><!-- BEGIN_IF [{url}/nem] --><a href="{url}" {attr} target="{target}"><!-- END_IF --><!-- END link#front -->
			{label}[raw]
			<!-- BEGIN link#front --><!-- BEGIN_IF [{url}/nem] --></a><!-- END_IF --><!-- END link#front -->
			<!-- BEGIN li#rear --></li><!-- END li#rear -->
	<!-- BEGIN ul#rear --></ul><!-- END ul#rear -->
<!-- END navigation:loop -->
<a href="#top" class="acms-hide-tb acms-hide-pc">メニューを閉じる</a>
</nav>
<!-- END_MODULE Navigation -->

<!-- BEGIN link#front --> 〜 <!-- END link#front --> の中に IFブロックを書いて、{url} が無い時に <a> を消すように修正します。<!-- BEGIN link#end --> </a> <!-- END link#end --> のままでは IFブロックの変数 {url} が出せないので、link#end のブロックは link#front に変更しています。

これで、通常の動きと、acms:// を書いた時どちらでも大丈夫なります。

navi.html の作成

<!-- BEGIN_MODULE Entry_List id="recruit_navi" -->
<a href="%{HOME_URL}recruit/">採用情報</a>
  <ul>
    <!-- BEGIN entry:loop -->
    <li class="js-link_match_location"><a href="{url}">{title}</a></li>
    <!-- END entry:loop -->
  </ul>
<!-- END_MODULE Entry_List -->

acms:// で「モジュールID」も設定できるようにすることができると汎用的に使えるテンプレートになるのですが、{{module_id}} のような変数が使える前の時代に用意され、変わっていない機能なので、ここでは recruit_navi のモジュールID固定で用意することになります。



acms://bid/1/cid/7/tpl/navi.html と書いてたので、カテゴリーID にチェックをつけていますが、モジュールID でカテゴリーを指定してしまう書き方でも大丈夫です。

acms://bid/1/field/gnavi/on/tpl/navi.html

また、field/name/value を追加してカスタムフィールドにチェックがあるものだけをメニューに表示させるような書き方もできます。

config.system.yaml の修正

最近のバージョンでは、tpl の利用について制限が加えられていますので、特定のファイルのみを tpl 利用可能に設定する必要があります。

allow_tpl_path

allow_tpl_path: [navi.html]

forbid_tpl_inheritance_when_path_unresolved や forbid_tpl_url_context が on の場合、除外するパスを設定します。例: [news.html,hoge/custom.html] カンマ区切りで指定

html_format_validate

html_format_validate: off

htmlフォーマットでない場合は404で返す設定になります。

この場合、include ディレクトリや admin のディレクトリにあるファイルなどがURLを指定すると表示できてしまう事になりますので、.htaccess などで表示できないように設定をするようにしてください。

Unit_List の使用ケースその2:Google MapのAPI 「MarkerClusterer」

エントリー内のユニットを表示するUnit_Listの使用ケース紹介その2では、Google MapのAPI 「MarkerClusterer」を使ったUnit_Listの活用方法をご紹介します。

たとえば、1つの地図に各エントリーに1つずつ挿入されている地図ユニットをピンでまとめたいときに有効です。

MarkerClustererを使うことにより、同じ位置にエントリーが集中していたとしてもピンが多くなりすぎず、すっきりとした見た目になります。


遠くのエントリーは1件表示だけですが、近くの2件はまとめて表示される

3件のエントリーに1つずつ地図が入力されている場合の MarkerClusterer の例


実装方法

/js/makerclusterer.jsと/images/フォルダをGitHubよりダウンロードしてください。

ソースコード:headタグ

headタグ内に以下を記述してください。

<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=%{GOOGLE_API_KEY}&sensor=false"></script> 
<script type="text/javascript" src="/js/markerclusterer.js"></script>

テーマフォルダに/images/フォルダを設置するときは、/js/makerclusterer.jsの以下の記述のパスを変更する必要があります(例: '/theme/site/images/m'; など)。

MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ = '../images/m';

ソースコード:MarkerClustererを設置したい場所への記述

HTMLファイル内のMarkerClustererを設置したい場所に以下を記述します。

<div id="map" style="height: 400px;"></div>

ソースコード:地図の基準にしたい緯度経度の情報を登録するカスタムフィールド

ブログのトップに表示させたい場合はブログのカスタムフィールドに、カテゴリーの一覧に表示させたい場合はカテゴリーのカスタムフィールドに記述してください。

※Site2016内の/admin/category/field_realestate.htmlと同じ内容です

<h3 class="acms-admin-admin-title2">一覧ページで表示させる地図の中心の緯度経度設定</h3>
<table class="adminTable acms-admin-table-admin-edit">
<tr>
  <th>地図</th>
  <td class="js-map-editable">
    <div class="acms-admin-form-group">
      <label for="input-text-map-search_text" class="acms-admin-hide-visually">住所で検索する</label>
      <input type="text" name="" value="" id="input-text-map-search_text" class="js-editable_map-search_text" disabled="disabled" size="40" />
      <input type="button" name="" value="検索" class="js-editable_map-search_button acms-admin-btn-admin" disabled="disabled" />
    </div>
    <div class="acms-admin-form-group">
      <img class="js-map_editable-container" src="http://maps.google.com/maps/api/staticmap?center={index_map_lat},{index_map_lng}&zoom={index_map_zoom}&size=640x400&maptype=roadmap&markers={index_map_lat},{index_map_lng}&key=%{GOOGLE_API_KEY}" width="640" height="400" style="display:block;" />
    </div>
  <!-- BEGIN index_map_lat:veil -->
  <label for="input-text-index_map_lat">緯度</label> <input type="text" name="index_map_lat" value="{index_map_lat}" size="9" id="input-text-index_map_lat" class="js-map_editable-lat" />
  <label for="input-text-index_map_lng">経度</label> <input type="text" name="index_map_lng" value="{index_map_lng}" size="10" id="input-text-index_map_lng" class="js-map_editable-lng" />
  <label for="input-text-index_map_zoom">ズーム</label> <input type="text" name="index_map_zoom" value="{index_map_zoom}" size="10" id="input-text-index_map_zoom" class="js-map_editable-zoom" />
  <!-- END index_map_lat:veil -->
  <!-- BEGIN index_map_lat:empty -->
  <label for="input-text-index_map_lat">緯度</label> <input type="text" name="index_map_lat" value="35.172775" size="9" id="input-text-index_map_lat" class="js-map_editable-lat" />
  <label for="input-text-index_map_lng">経度</label> <input type="text" name="index_map_lng" value="136.887466" size="10" id="input-text-index_map_lng" class="js-map_editable-lng" />
  <label for="input-text-index_map_zoom">ズーム</label> <input type="text" name="index_map_zoom" value="7" size="10" id="input-text-index_map_zoom" class="js-map_editable-zoom" />
  <!-- END index_map_lat:empty -->
  <input type="hidden" name="field[]" value="index_map_lat" />
  <input type="hidden" name="field[]" value="index_map_lng" />
  <input type="hidden" name="field[]" value="index_map_zoom" />
  </td>
</tr>
</table>

ソースコード:MarkerClustererを動かすためのJavaScript(ここではHTMLファイルとして使用します。例:map.html)

<script type="text/javascript">
  var map = null;
  var markerclusterer = null;
  var infowindow = new google.maps.InfoWindow();
  var gmarkers = []; 
  // マーカーの作成と、吹き出しの作成
  function createMarker(latlng, info) {
    var marker = new google.maps.Marker({
      position: latlng,
      map: map
    });
    google.maps.event.addListener(marker, 'click', function() {
      infowindow.setContent(info); 
      infowindow.open(map,marker);
    });
    // 情報を保存
    gmarkers.push(marker);
  }
  // クリックイベントを作成する
  function myclick(i) {
    google.maps.event.trigger(gmarkers[i], "click");
  }
  function initialize() {
    // 全体の地図を作成
    <!-- BEGIN_MODULE Category_Field -->
    var myOptions = \{
      zoom: {index_map_zoom},
      center: new google.maps.LatLng({index_map_lat},{index_map_lng}),
      mapTypeControl: true,
      navigationControl: true,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    \}<!-- END_MODULE Category_Field -->
    map = new google.maps.Map(document.getElementById("map"), myOptions);
    google.maps.event.addListener(map, 'click', function() {
      infowindow.close();
    });
    // 場所・吹き出しの情報を定義
    var markers = [
    <!-- BEGIN_MODULE Unit_List id="map" --><!-- BEGIN unit:loop -->
      ["{entry_title}", {unit_field_2},{unit_field_3},"{entry_url}"],<!-- END unit:loop -->[]<!-- END_MODULE Unit_List -->
    ];
    // 吹き出しに入れる要素
    for (var i = 0; i < markers.length; i++) {
      var point = new google.maps.LatLng( markers[i][1],  markers[i][2]);
      var marker = createMarker( point, "<div class='scrollFix'><p class='mapEntryTitle'>" + markers[i][0] + "</p> " + "<p class='mapDetailInfo'>緯度: " + markers[i][1] + "<br> 経度: "  +  markers[i][2] + "</p><p class='mapLinkText'><a href='"+ markers[i][3] +"'>詳しく見る</a></p>" + " </div>") ;
    }
    markers.pop();
    // 地図を表示
    markerCluster = new MarkerClusterer(map, gmarkers);
  }
  window.addEventListener('load', initialize);
</script>

注意点

  • 「MarkerClustererを動かすためのJavaScript」のソースコードは、全てJavaScriptで書かれていますが a-blog cms のモジュールを使っているためHTMLファイル内に記述します
  • 25行目ではCategory_Fieldを使用していますが、もし「地図の基準にしたい緯度経度の情報を登録するためのカスタムフィールド」をカテゴリー以外のカスタムフィールドとして設置した場合、対応するフィールドモジュールに置き換えます

モジュールIDの設定

モジュールID名「map」というUnit_Listのモジュールを作ります。


ユニットタイプの「地図」がチェックされていることを確認してください。

そのほかの設定については、必要に応じて有効にしてください。

モジュールID名に「ctx」が含まれているとctx指定が読み込めなくなる

ID名「test_module_ctx」でモジュール作成している画面


システムの仕様上、モジュールID名に「ctx」を含ませるとテンプレートでのctx指定が読み込めなくなりますのでご注意ください。

NG

<!-- BEGIN_MODULE *** id="test_module_ctx" ctx="bid/1/cid/6" -->
<!-- END_MODULE *** -->

OK

<!-- BEGIN_MODULE *** id="test_module" ctx="bid/1/cid/6" -->
<!-- END_MODULE *** -->

今後ともa-blog cmsをよろしくお願いいたします。

「今いるページ / 全ページ数」を表示させるページャーのカスタマイズ


標準のページャーの設定では、上記の画像のように 1 2 3 4 のように表示され、今いるページのスタイルが違うような表示になるようになっています。先日サポートで、これを 1 / 4 と表示させたいという相談があり、その対応が簡単に思いつかなかったのでブログに書き残しておきます。

Entry_Summary のコンフィグ 初期設定



利用できる変数を考える

表示させる 1 / 4 は「現在表示しているページ / 全ページ数」ということになります。

「現在表示しているページ」については、Entry_Summary の変数にはありませんが、グローバル変数に %{PAGE} というものが用意されていますので、これを利用ください。



問題は「全ページ数」です。Entry_Summary の変数表に以下のような {lastPage} という設定があります。これがページ数が少ない時に初期の設定では表示ができない仕様になっております。これを強制的に表示するための設定するための「前後に表示するページ数」に -1 を設定することで目的の動きになります。

カスタマイズ設定

Entry_Summary のコンフィグ設定



テンプレートへの記述

<p class="acms-text-center">%{PAGE} / {lastPage}</p>

これで当初の目的である 1 / 4 が表示可能になります。


Unit_List の使用ケースその1:ギャラリー

Unit_Listとは、ビルトインモジュールの1つで、現段階では Entry_Body 以外で唯一ユニットを表示できるモジュールです。Entry_Body と違うところは、Entry_Body はエントリーのユニットを表示するのに対し、 Unit_List はエントリーをまたぎ、ユニットのみを表示して一覧にすることができます。

Unit_List は特殊なモジュールのため、どう応用していいのか想像がつきづらいかと思いますが、その1例として、ギャラリーページに使われます。


(スクリーンショット:写真が並んだギャラリーページ)

ユニットリストをギャラリーとして利用した例


実装方法

まずは、ギャラリーを表示したい場所に、ユニットリストを実装したファイルをインクルード機能を使って読み込みます。

インクルードファイルが /include/unit_list.html の場合、ソースコードは以下のようになります(※ファイルのパス、ファイル名が違う場合は30行目を修正してください)。

ソースコード(/include/unit_list.html)

<script>
  ACMS.Ready(function(){
    ACMS.Config.ppMark = 'a[data-rel^="prettyPhoto"]';
  });
</script>
<!-- BEGIN_MODULE Unit_List id="gallery" -->
<div class="acms-container">
  <!--#include file="/admin/module/setting.html"-->
  <div class="acms-grid">
    <!-- BEGIN unit:loop -->
    <div class="acms-col-md-4 acms-col-sm-6 text-center" style="position: relative;"> 
      <a href="<!-- BEGIN_IF [{large}/nem/] -->%{ARCHIVES_DIR}{large}<!-- ELSE -->%{ARCHIVES_DIR}{normal}<!-- END_IF -->" data-rel="prettyPhoto[gallery{entry_id}]" title="{entry_title}" >
          <p class="acms-text-center"><!-- #BEGIN image:veil -->
            <img src="%{ARCHIVES_DIR}{normal}[resizeImg(200,200)]" alt="{alt}"  class="acms-img-rounded"><!-- #END image:veil -->
          </p>
      </a>
      <!-- BEGIN_MODULE Touch_SessionWithAdministration -->
      <!-- 編集ボタン -->
      <form action="" method="post" style="position: absolute; bottom: 20px; right: 15px;">
        <input type="hidden" name="eid" value="{entry_id}" />
        <input type="hidden" name="admin" value="entry-edit" />
        <input type="submit" name="ACMS_POST_2GET" value="変更する" class ="acms-admin-btn" />
      </form>
      <!-- END_MODULE Touch_SessionWithAdministration -->
    </div>
    <!-- END unit:loop -->
  </div>
 
  <!-- 続きを読むボタン -->
  <!-- BEGIN pager:veil --><!-- BEGIN forwardLink -->
  <form action="" method="post" class="js-post_include">
    <input type="hidden" name="bid" value="%{BID}" />
    <input type="hidden" name="cid" value="%{CID}" />
    <input type="hidden" name="tpl" value="/include/unit_list.html" />
    <input type="submit" name="ACMS_POST_2GET" value="もっと見る" class="acms-btn acms-btn-block acms-btn-large" />
    <input type="hidden" name="page" value="{forwardPage}" />
  </form>
  <!-- END forwardLink --><!-- END pager:veil -->
</div>
<!-- END_MODULE Unit_List -->

注意点

  • モジュールID名を修正するときは6行目を変更してください(現在のモジュールID名は「gallery」になっています)
  • 1~5行目では、prettyPhotoはHTML5対応するため、12行目のrel属性をdata-rel属性に変更しています
  • ファイルのパス、ファイル名が違う場合は34行目を修正してください

モジュールの設定



ユニットタイプの「画像」がチェックされていることを確認してください。

他の設定については、必要に応じて有効にしてください。


Unit_List を使うことで変わるギャラリーページの運用方法


Unit_Listをギャラリーページで使うことになると、基本的にはエントリーのページでは文字を挿入することがなくなります。運用時に運営者が迷わないように、管理画面>コンフィグ>編集設定の順にページを移動し、「画像」以外のユニット追加ボタンを削除しましょう。


編集設定のページにある、ユニット追加ボタンを「画像」以外削除しておく


エントリー編集画面のユニット追加ボタン


このように画像投稿専用のUIが運営者に提供できます。

次のバージョンではJSONやXMLが処理できるモジュールが用意される


これまでのモジュール開発では写真のような感じでモジュールを書いていました。これを、もっと簡単に効率的にモジュールが作れるようになる事が勉強会の中で発表がありました。

【ver2.1.0以降】フォームモジュールの仕様変更について

フォームモジュールの仕様変更

a-blog cms ver2.1.0 より フォームモジュールのセキュリティ対策の為仕様が 変更されてますので、開発時、アップデート時にご注意下さい。

仕様変更部分

フォームモジュール内のステップブロックは自由な文字列でよかったのですが、version2.1.0より 確認画面のブロックが必須になり、確認画面のブロック名が「confirm」で固定になります。

また新たなブロックとして「forbidden」ブロックが追加されました。 これは不正な送信を検知した場合に表示されるブロックになります。

<!-- 必須ブロック -->
<!-- BEGIN step#confirm --><!-- END step#confirm -->

<!-- 追加ブロック -->
<!-- BEGIN step#forbidden --><!-- END step#forbidden -->

この仕様に当てはまらないカスタマイズをされている場合は、修正をお願い致します。 また、バージョンアップ時の注意事項としてマニュアルにも追記しますので、ご注意お願い致します。

エントリーユニットの途中に別のモジュールを入れる

エントリーのユニットとユニットの間に、バナーモジュールや一覧など何か別のモジュールを表示したい場合の方法を説明します。
本機能はver2.1.1で追加されましたbuildTplの校正オプションを利用します(ver2.1.1のリリースノート)。

2.0系のRSSモジュールで不具合が見つかりました。

2.0系の一部モジュールに不具合が見つかりました。

バージョン2.0.0、2.0.0.1, 2.0.0.2のRSSで本文が表示されない不具合が 発見されました。2.0.0.3にアップデート、または2.0.0.3の特定のファイルを差し替えて 対応をお願いいたします。

対応方法

以下のダウンロードページよりv2.0.0.3をダウンロード。

http://www.a-blogcms.jp/download/

v2.0.0.3にアップデート。または、/themes/system/rss2.xml をv2.0.0.3のものに置き換える。

この度は大変ご迷惑をお掛けしてしまい申し訳ございません。

今後ともa-blog cmsをよろしくお願い致します。

2.0系のRSSモジュールで不具合が見つかりました。

2.0系の一部モジュールに不具合が見つかりました。

バージョン2.0.0、2.0.0.1, 2.0.0.2のRSSで本文が表示されない不具合が 発見されました。2.0.0.3にアップデート、または2.0.0.3の特定のファイルを差し替えて 対応をお願いいたします。

対応方法

以下のダウンロードページよりv2.0.0.3をダウンロード。

http://www.a-blogcms.jp/download/

v2.0.0.3にアップデート。または、/themes/system/rss2.xml をv2.0.0.3のものに置き換える。

この度は大変ご迷惑をお掛けしてしまい申し訳ございません。

今後ともa-blog cmsをよろしくお願い致します。