CMSで更新する予定のコンテンツで、上の画像のように
「『お客様の声』や『ボタン』のパーツを、本文中の好きな場所に表示したい」
と要望があったら、どう対応しますか。

カスタムフィールドだと、表示位置をあらかじめ固定しなければなりません。
WordPressの「AddQuicktag」や、ウィジウィグのテンプレート機能は、HTMLを編集できるためページが崩れる危険性が高くなります。

ブロック単位の編集ができるCMS、concrete5や、WordPressのプラグイン「Page Builder」なら解決するように思えます。しかし、いずれも独自の入力欄を持ったパーツを作ろうとすると、専用のプログラムを書くことになり、制作コストがかかります。

a-blog cmsはバージョン2.1から、自作のユニット(パーツ)を追加できる「カスタムユニット」機能が追加されました。

冒頭のような要望を簡単に実装でき、制作者・更新担当者をどちらも幸せにする、おすすめの機能です。使い方を詳しくご紹介します。

メリット

PHPを書かない
HTMLと条件分岐などの基礎知識があれば実装できます。書くのはa-blog cmsの独自タグのみで、PHPは一切書きません。間違えてもサイトが真っ白になることはありません。
UIを自由に作成できる
form要素のルールさえ守っていれば、ユーザーインターフェースは制作者が決められます。通常は管理画面用のCSSフレームワーク「acms.css」で充分ですが、外部のUIも実装できます。
モバイル対応
「acms.css」はレスポンシブWebデザインで設計されています。このため、カスタムユニットもスマートフォンやタブレットでの更新に対応できます。
タグがカスタムフィールドとほぼ同じ
カスタムユニット専用のタグは、開始・終了のみです。既存のカスタムフィールドと同じHTML構造なので、a-blog cmsを学習したことがあれば、コストはかかりません。
使い回しがきく
基本はHTMLファイルなので、一度作成するとその後の案件でも簡単に複製・改変できます。後述する「ボタン」は要望が多いので、作っておいて損はありません。

デメリット

いろいろ考えましたが、この機能には大きなデメリットがありません。

フィールド検索の対象にできない
カスタムユニットで入力したデータは通常の全文検索にはヒットしますが、カスタムフィールド別検索の対象にはできません。物件・書籍情報など、絞り込みが必要なコンテンツには利用しないようにしてください。
iOSアプリが使えない
a-blog cmsのiOSアプリは、公式ユニットのみ対応しています。カスタムユニットを実装したサイトは、Safariなどのブラウザでログインして更新することになります。

カスタムユニット作成の流れ

ID・入力項目を考える

最初に、ユニットに対する一意のIDを考えます。基本的に英語・数字・アンダーバーを使います。ボタンなら「button」、吹き出しなら「balloon」などとすればよいでしょう。
ここでは便宜上「hoge」で説明します。
また、どのような入力項目が必要かも考えておきましょう。ボタンなら、ボタンの文字列とリンク先URLのテキスト入力が必要です。

編集画面用のテンプレートを作る

編集画面用のテンプレートを作ります。テキストエディタで新規HTMLファイルを作成し、以下のコードを貼り付けてください。

<!-- BEGIN custom_hoge -->
<table class="entryFormColumnSettingTable entryFormColumnTable">
	<tr>
		<td class="entryFormFileControl">
			<table class="entryFormColumnSettingTable">

				<!-- 入力項目 -->

			</table>
		</td>
	</tr>
</table>
<!-- END custom_hoge -->

a-blog cmsのフレームワークのコードを流用していますが、CSSのカスタマイズをする余裕があるなら、マークアップに大きな制限はありません。
重要なのは「BEGIN」「END」と書かれている、HTMLのコメントを模した開始・終了タグです。ここに入るコードネームは必ず「custom_考えておいたID」としてください。

作成したテンプレートを、カスタムユニットを実装したいテーマに、以下のパス・ファイル名で保存してください。ディレクトリがない場合は作成します。テンプレートファイル名は変更できません。

/テーマのディレクトリ/admin/entry/unit/extend.html

表示用のテンプレートを作る

表示用のテンプレートを作ります。テキストエディタで新規HTMLファイルを作成し、以下のコードを貼り付けてください。

<!-- BEGIN unit#custom_hoge -->

<!-- ユニットの表示 -->

<!-- END unit#custom_hoge -->

こちらにも開始・終了タグがあるので同様に「custom_考えておいたID」としてください。

作成したテンプレートを、制作中のテーマに以下のパス・ファイル名で保存してください。ディレクトリがない場合は作成します。テンプレートファイル名は変更できません。

/テーマのディレクトリ/include/unit/extend.html

編集設定にユニットを追加する

ここで一旦、a-blog cmsにログインし、管理ページ内の「コンフィグ > 編集設定」へ移動してください。

ページ冒頭に、サイト内で利用可能なユニットの追加画面があります。スクリーンショットの通りに新しいユニットを追加し、モードのプルダウンを「拡張」、IDの入力欄に先ほどの「custom_考えておいたID」を入力してください。
プルダウンには「カスタム」というものもありますが「拡張」です。間違えないようにしてください。

ラベルは、更新担当者向けのユニットの表示名です。わかりやすく簡潔な名前にしてください。

ユニット設定にユニットを追加する

続いて、同じく管理ページ内の「コンフィグ > ユニット設定」へ移動してください。

ページをスクロールしていくと、先ほど追加したユニット項目が見つかるはずです。また、それぞれの項目についている「ユニットの追加ボタン」にもボタンが増えています。

ボタンを押してみると、見出しだけの項目が追加されます。この状態を確認したら「保存」ボタンを押して更新してください。

編集画面用テンプレートにフォームを追加する

いよいよ、編集画面のフォームを作成していきます。

a-blog cmsは、入力画面のスニペットを自動生成してくれるツールが管理画面内に用意されています。
「コンフィグ > カスタムフィールドメーカー」にありますが、ここではいろいろな入力フォームを全部盛りしているサンプルコードを出してしまいます。

以下のコードを、編集画面用の「extend.html」内の「<!– 入力項目 –>」のところにコピー・ペーストしてください。

<!-- ユニットの入力項目:テキストの場合 -->
<tr>
	<th style="white-space: nowrap;">テキスト</th>
	<td>
		<input type="text" name="hoge_text{id}" value="{hoge_text}" class="acms-admin-form-width-full" />
		<input type="hidden" name="unit{id}[]" value="hoge_text{id}" />
	</td>
</tr>

<!-- ユニットの入力項目:テキストエリアの場合 -->
<tr>
	<th style="white-space: nowrap;">テキストエリア</th>
	<td>
		<textarea name="hoge_textarea{id}" class="acms-admin-form-width-full" rows="5">{hoge_textarea}[raw]</textarea>
		<input type="hidden" name="unit{id}[]" value="hoge_textarea{id}" />
	</td>
</tr>

<!-- ユニットの入力項目:画像の場合 -->
<tr>
	<th style="white-space: nowrap;">画像</th>
	<td class="js-img_resize_cf">
		<!-- BEGIN_IF [{hoge_img@tinyPath}/em] -->
		<img src="" style="display:none; max-width: 150px;" class="js-img_resize_preview acms-admin-img-responsive" />
		<!-- END_IF -->
		<!-- BEGIN_IF [{hoge_img@path}/nem] -->
		<img src="%{ARCHIVES_DIR}{hoge_img@tinyPath}" class="js-img_resize_preview acms-admin-img-responsive" />
		<input type="hidden" name="hoge_img{id}@old" value="{hoge_img@path}" />
		<label class="acms-admin-form-checkbox">
			<input type="checkbox" name="hoge_img{id}@edit" value="delete" />
			<i class="acms-admin-ico-checkbox"></i> 削除
		</label>
		<!-- END_IF -->
		<input type="file" name="hoge_img{id}" size="20" class="js-img_resize_input" /><br />
		代替テキスト:<input type="text" name="hoge_img{id}@alt" value="{hoge_img@alt}" size="40" />
		<input type="hidden" name="unit{id}[]" value="hoge_img{id}" />
		<input type="hidden" name="hoge_img{id}:extension" value="image" />
		<input type="hidden" name="hoge_img{id}@width" value="960" />
		<input type="hidden" name="hoge_img{id}@tinyWidth" value="150" />
		<input type="hidden" name="hoge_img{id}@filename" value="" />
	</td>
</tr>

<!-- ユニットの入力項目:チェックボックスの場合 -->
<tr>
	<th style="white-space: nowrap;">チェックボックス</th>
	<td>
		<label class="acms-admin-form-checkbox" for="input-hoge_check{id}">
		<input type="checkbox" name="hoge_check{id}[]" value="1" id="input-hoge_check{id}"{hoge_check:checked#1} />
		<i class="acms-admin-ico-checkbox"></i>チェックを入れると値に1が入ります
		</label>
		<input type="hidden" name="unit{id}[]" value="hoge_check{id}" />
	</td>
</tr>

<!-- ユニットの入力項目:ラジオボタンの場合 -->
<tr>
	<th style="white-space: nowrap;">ラジオボタン</th>
	<td>
		<label class="acms-admin-form-radio"><input type="radio" name="hoge_radio{id}" value=""<!-- BEGIN_IF [{hoge_radio}/em] --> checked="checked"<!-- END_IF --> /><i class="acms-admin-ico-radio"></i>選択肢null</label>
		<label class="acms-admin-form-radio"><input type="radio" name="hoge_radio{id}" value="選択肢1"{hoge_radio:checked#選択肢1} /><i class="acms-admin-ico-radio"></i>選択肢1</label>
		<label class="acms-admin-form-radio"><input type="radio" name="hoge_radio{id}" value="選択肢2"{hoge_radio:checked#選択肢2} /><i class="acms-admin-ico-radio"></i>選択肢2</label>
		<label class="acms-admin-form-radio"><input type="radio" name="hoge_radio{id}" value="選択肢3"{hoge_radio:checked#選択肢3} /><i class="acms-admin-ico-radio"></i>選択肢3</label>
		<input type="hidden" name="unit{id}[]" value="hoge_radio{id}" />
	</td>
</tr>

<!-- ユニットの入力項目:セレクトボックスの場合 -->
<tr>
	<th style="white-space: nowrap;">セレクトボックス</th>
	<td>
		<select name="hoge_select{id}" class="acms-admin-form-width-full">
		<option value="">(選択してください)</option>
		<option value="選択肢1"{hoge_select:selected#選択肢1}>選択肢1</option>
		<option value="選択肢2"{hoge_select:selected#選択肢2}>選択肢2</option>
		<option value="選択肢3"{hoge_select:selected#選択肢3}>選択肢3</option>
		</select>
		<input type="hidden" name="unit{id}[]" value="hoge_select{id}" />
	</td>
</tr>

<!-- ユニットの入力項目:PDFファイルの場合 -->
<tr>
	<th style="white-space: nowrap;">PDFファイル</th>
	<td>
		<!-- BEGIN_IF [{hoge_file@path}/nem] -->
		<input type="hidden" name="hoge_file{id}@old" value="{hoge_file@path}" />
		<input type="hidden" name="hoge_file{id}@secret" value="{hoge_file@secret}" />
		<input type="hidden" name="hoge_file{id}@fileSize" value="{hoge_file@fileSize}" />
		<label for="input-checkbox-hoge_file@edit" class="acms-admin-form-checkbox">
		<input type="checkbox" name="hoge_file{id}@edit" value="delete" id="input-checkbox-hoge_file@edit" />
		<i class="acms-admin-ico-checkbox"></i> 削除
		</label>
		<a href="%{ARCHIVES_DIR}{hoge_file@path}"><img src="/images/fileicon/pdf.gif" width="64" height="64" alt="pdf" /></a>
		{hoge_file@baseName}<br />
		<!-- END_IF -->
		<input type="file" name="hoge_file{id}" size="20" />
		<input type="hidden" name="unit{id}[]" value="hoge_file{id}" />
		<input type="hidden" name="hoge_file{id}@baseName" value="{hoge_file@baseName}" />
		<input type="hidden" name="hoge_file{id}:extension" value="file" />
		<input type="hidden" name="hoge_file{id}@extension" value="pdf" />
	</td>
</tr>

それぞれのフォーム項目には一意のIDを設けます。「考えておいたID_項目名」とするとわかりやすいです。例えば、ボタンユニットのURLだと「button_url」、フキダシユニットの人物画像だと「balloon_img」となります。

コーディングに慣れている人だとすぐ気付くと思いますが、上記スニペットの「hoge_」を置換するだけで流用できます。

出力用テンプレートの体裁を整える

続いて、出力用テンプレートを作っていきます。

こちらも先述の「カスタムフィールドメーカー」を使うことができますが、案件によってマークアップは全く変わってきます。今回は単純に表で一覧させるコードにしてみました。

以下のコードを、出力用の「extend.html」内の「<!– ユニットの表示 –>」のところにコピー・ペーストしてください。

<table class="acms-table acms-table-borderd">

	<!-- ユニットの表示:テキストの場合 -->
	<tr>
		<th>テキスト</th>
		<td>
			{hoge_text}
		</td>
	</tr>

	<!-- ユニットの表示:テキストエリアの場合 -->
	<tr>
		<th>テキストエリア</th>
		<td>
			{hoge_textarea}[nl2br|raw]
		</td>
	</tr>

	<!-- ユニットの表示:画像の場合 -->
	<tr>
		<th>画像</th>
		<td>
			<!-- BEGIN_IF [{hoge_img@largePath}/nem] -->
			<img src="%{ARCHIVES_DIR}{hoge_img@largePath}" alt="{hoge_img@alt}" class="acms-img-responsive" />
			<!-- END_IF -->
		</td>
	</tr>

	<!-- ユニットの表示:チェックボックスの場合 -->
	<tr>
		<th style="white-space: nowrap;">チェックボックス</th>
		<td>
			<!-- BEGIN_IF [{hoge_check}/eq/1] -->
			チェックが入っています
			<!-- ELSE -->
			<strong>チェックが入っていません</strong>
			<!-- END_IF -->
		</td>
	</tr>

	<!-- ユニットの表示:ラジオボタンの場合 -->
	<tr>
		<th>ラジオボタン</th>
		<td>
			<!-- BEGIN_IF [{hoge_radio}/em] -->
			選択肢Null
			<!-- ELSE -->
			<strong>{hoge_radio}</strong>
			<!-- END_IF -->
		</td>
	</tr>

	<!-- ユニットの表示:セレクトボックスの場合 -->
	<tr>
		<th>セレクトボックス</th>
		<td>
			<!-- BEGIN_IF [{hoge_select}/em] -->
			選択肢Null
			<!-- ELSE -->
			<strong>{hoge_select}</strong>
			<!-- END_IF -->
		</td>
	</tr>

	<!-- ユニットの表示:PDFファイルの場合 -->
	<tr>
		<th>PDFファイル</th>
		<td>
			<!-- BEGIN_IF [{hoge_file@path}/nem] -->
			<a href="%{ARCHIVES_DIR}{hoge_file@path}" target="_blank"><img src="/images/fileicon/pdf.gif" width="64" height="64" alt="pdf" /></a>
			<!-- END_IF -->
		</td>
	</tr>

</table>

投稿テストをしてみる

これで、カスタムユニットの準備ができました。
実際にエントリーを作成して、ユニットが正しく表示されるか、入力した内容が保存されるか確認してください。

実際の表示画面に表が出てくるか、入力内容が反映されるか、ダイレクト編集機能でも更新できるかもチェックしてください。

まとめ

カスタムユニットの解説は以上です。

サンプルコードを流用すれば、だいたいのユニットは数十分くらいで作ることができます。予算や工数でこういった要望を断ってきた経験がある人には、ありがたい機能ではないかと思います。

最初の方にスクリーンショットを出した「ボタンユニット」のサンプルコードを、Gistで公開しています。bootstrapなどの他のフレームワークにも対応できますので、こちらも自由にお使いください。

a-blog cmsのカスタムユニット:ボタン | webbingstudio’s gists

この記事を書いた人

うぇびん

愛知県豊橋市に住んでいる、荒ぶるウェブおばさん。WordPressをはじめとした各種CMSを研究するのが好き。札幌のIT企業のビットスター株式会社に所属しています。