カスタムフィールドグループ
カスタムフィールドグループとは、単体の項目であるカスタムフィールドを複数まとめて取り扱うことができる機能です。カスタムフィールドの項目を追加したり、削除したりすることができます。
カスタムフィールドグループはカスタムフィールドと同じように画像やテキストのカスタムフィールドを組み合わせて使えます。
例)画像とテキスト、テキストエリアを組み合わせたカスタムフィールドグループです。
<table class="js-fieldgroup-sortable"> <!-- BEGIN bfd_field_unit_group:loop --> <tr class="sortable-item"> <td class="item-handle"> <div class="acms-form-group"><span class="acms-icon acms-icon-sort2"></span></div> <a class="item-delete acms-btn-admin acms-btn-admin-danger block-level" href="#" onclick="return false;">削除</a> </td> <td> <table class="nestTable"> <tr> <th>小画像</th> <th>小見出しとURL</th> <th>小概要</th> </tr> <tr> <td> <!-- BEGIN bfd_field_unit_image:veil --> <img src="%{ARCHIVES_DIR}{bfd_field_unit_image@path}" /> <!-- END bfd_field_unit_image:veil --> <br /> <label><input type="checkbox" name="bfd_field_unit_image@edit[{i}]" value="delete" />削除</label> <input type="file" name="bfd_field_unit_image[{i}]" class="acms-form-width-full" /> <input type="hidden" name="bfd_field_unit_image@width[{i}]" value="200" /> </td> <td> <div class="acms-form-group"> <input type="text" name="bfd_field_unit_lead[{i}]" value="{bfd_field_unit_lead}" class="acms-form-width-full" /> </div> <input type="text" name="bfd_field_unit_url[{i}]" value="{bfd_field_unit_url}" class="acms-form-width-full" /> </td> <td> <textarea name="bfd_field_unit_summary[{i}]" class="acms-form-width-full" >{bfd_field_unit_summary}</textarea> </td> </tr> </table> </td> </tr> <!-- END bfd_field_unit_group:loop --> <tr class="sortable-item item-template"> <td class="item-handle"> <span class="acms-icon acms-icon-sort2"></span> </td> <td> <table> <tr> <th>小画像</th> <th>小見出しとURL</th> <th>小概要</th> </tr> <tr> <td> <input type="file" name="bfd_field_unit_image[]" class="acms-form-width-full" /> <input type="hidden" name="bfd_field_unit_image@width[]" value="200" /> </td> <td> <div class="acms-form-group"> <input type="text" name="bfd_field_unit_lead[]" value="" class="acms-form-width-full" /> </div> <input type="text" name="bfd_field_unit_url[]" value="" class="acms-form-width-full" /> </td> <td> <textarea name="bfd_field_unit_summary[]" class="acms-form-width-full" ></textarea> </td> </tr> </table> <input type="hidden" name="bfd_field_unit_image@old[{i}]" value="{bfd_field_unit_image@path}" /> </td> </tr> <tfoot> <tr> <td colspan="3"> <input type="button" class="item-insert acms-btn-admin" value="項目を追加する" /> </td> </tr> </tfoot> </table> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_lead" /> <input type="hidden" name="field[]" value="bfd_field_unit_lead" /> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_url" /> <input type="hidden" name="field[]" value="bfd_field_unit_url" /> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_summary" /> <input type="hidden" name="field[]" value="bfd_field_unit_summary" /> <input type="hidden" name="bfd_field_unit_image:extension" value="image" /> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_image@path" /> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_image@x" /> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_image@y" /> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_image@edit" /> <input type="hidden" name="@bfd_field_unit_group[]" value="bfd_field_unit_image@old" /> <input type="hidden" name="field[]" value="bfd_field_unit_image" /> <input type="hidden" name="field[]" value="@bfd_field_unit_group" />
カスタムフィールドグループ内で使用可能なclass属性
カスタムフィールドグループ内では、いくつかの特殊なclass属性の記述があります。これらは、実際にブラウザ上で表示される際に機能します。
js-fieldgroup-sortable
このclass属性が適用されている範囲内で、カスタムフィールドグループが使用できます。 ひな形となり、この要素の内容が追加されます。
item-handle
このclass属性が記述されている要素が、順番を変更する時に「つかむ(ドラッグする)」部分になります。js-fieldgroup-sortable内で使用可能です。
item-delete
このclass属性が記述されている要素で、該当するカスタムフィールドグループが削除できます。js-fieldgroup-sortable内で使用可能です。
item-max
このclass属性が記述されている要素のvalueにある値がカスタムフィールドグループに挿入できる項目の最大数となります。例えば以下のソースコードで、7以上の項目を追加しようとすると警告文が表示されます。js-fieldgroup-sortable内で使用可能です。
<input type="hidden" class="item-max" value="6" />

例で使用したカスタムフィールドの解説
カスタムフィールドの定義
カスタムフィールドのグループ名(@bfd_field_unit_group)とカスタムフィールド変数名(bfd_field_unit_lead)をセットで定義します。
<input type="hidden" name="@カスタムフィールドのグループ名[]" value="カスタムフィールド変数名" /> <input type="hidden" name="field[]" value="カスタムフィールド変数名" />
カスタムフィールドのグループ名(@bfd_field_unit_group)はカスタムフィールドのグループ名を記述しています。
<input type="hidden" name="field[]" value="@カスタムフィールドのグループ名" />
テンプレートに表示する
エントリーカスタムフィールドで作成した場合は、Entry系モジュールのentry:loop内にカスタムフィールドグループを記述してください。
<!-- BEGIN bfd_field_unit_group:loop --> <div style="width:200px; float:left; margin-right:20px;"> <!-- BEGIN bfd_field_unit_image:veil --> <img src="%{ARCHIVES_DIR}{bfd_field_unit_image@path}" alt="" width="200"> <!-- END bfd_field_unit_image:veil --> <h3><a href="%{HTTP_ROOT}{bfd_field_unit_url}">{bfd_field_unit_lead}</a></h3> <p>{bfd_field_unit_summary}</p> </div> <!-- END bfd_field_unit_group:loop -->

上記のような bfd_field_unit_group:loop のブロック中に変数を書くことで複数件のデータを表示させるのがカスタムフィールドグループの利用としては一般的ですが、ループさせずに 2番目だけ 表示させたいという場合には、{bfd_field_unit_lead[1]} のような記述でも「小見出し2です」を表示させることが可能です。(配列の添字は 0 から始まります)
カスタムユニットを動的化してみよう
通常カスタムユニットを変更しようと思った場合にはテンプレートを修正する必要が出てきます。ですがカスタムユニットの項目をカスタムフィールドで作ることによってテンプレートを触ることなくカスタムユニットの内容を変更できるようになります。
ハンズオン概要
今回は動的カスタムユニットを使ってインタビュー記事を作成していきます。カスタムユニットの完成イメージはこちらです。
今回動的化する箇所は画像になります。画像をブログのカスタムフィールドで登録できるようにし、その登録内容をカスタムユニットに表示できるように実装していきましょう。今回使用するテクニックは エスケープと Set Rendered / Get Rendered になります。
ブログのカスタムフィールド
この記事で使用しているテーマはbeginner2019ですが他のテーマで実施していただいても問題ありません。
まずは、画像の選択肢を追加するためのカスタムフィールドを作っていきます。カスタムフィールドメーカーを使ってソースコードを生成することもできますが、今回は下記ソースコードを使用してください。
下記入力用ソースを /themes/beginner2019/admin/blog/field.html に追加してください。
<!-- スタッフリスト --> <h2 class="acms-admin-admin-title2">スタッフリスト</h2> <table class="js-fieldgroup-sortable adminTable acms-admin-table-admin-edit"> <thead class="acms-admin-hide-sp"> <tr> <th class="acms-admin-table-left acms-admin-admin-config-table-item-handle"> </th> <th class="acms-admin-table-left">コード</th> <th class="acms-admin-table-left">画像</th> <th class="acms-admin-table-left">名前</th> <th class="acms-admin-table-left acms-admin-admin-config-table-action">削除</th> </tr> </thead> <tbody> <!-- BEGIN group_staff:loop --> <tr class="sortable-item"> <td class="item-handle acms-admin-table-nowrap"> <i class="acms-admin-icon-sort"></i> </td> <td> <input type="text" name="group_staff_code[]" value="{group_staff_code}" class="acms-admin-form-width-sm" /> </td> <td class="js-media-field"> <div class="js-droparea" data-thumbnail="{group_staff_img@thumbnail}" data-type="image" style="width:150px"></div> <p class="js-text acms-admin-text-danger" style="display:none">許可されていないファイルのため挿入できません。</p> <div class="acms-admin-margin-top-mini"> <button type="button" class="js-insert acms-admin-btn" data-type="image">選択</button> </div> <input type="hidden" name="group_staff_img[]" value="{group_staff_img}" class="js-value" /> </td> <td> <input type="text" name="group_staff_name[]" value="{group_staff_name}" class="acms-admin-form-width-full" /> </td> <td class="acms-admin-table-nowrap"> <input type="button" class="item-delete acms-admin-btn-admin acms-admin-btn-admin-danger" value="削除" /> </td> </tr> <!-- END group_staff:loop --> <tr class="sortable-item item-template"> <td class="item-handle acms-admin-table-nowrap"> <i class="acms-admin-icon-sort"></i> </td> <td> <input type="text" name="group_staff_code[]" value="" class="acms-admin-form-width-full" /> </td> <td class="js-media-field"> <div class="js-droparea" data-type="image" style="width:150px"></div> <p class="js-text acms-admin-text-danger" style="display:none">許可されていないファイルのため挿入できません。</p> <div class="acms-admin-margin-top-mini"> <button type="button" class="js-insert acms-admin-btn" data-type="image">選択</button> </div> <input type="hidden" name="group_staff_img[]" value="" class="js-value" /> </td> <td> <input type="text" name="group_staff_name[]" value="" class="acms-admin-form-width-full" /> </td> <td class="acms-admin-table-nowrap"> <input type="button" class="item-delete acms-admin-btn-admin acms-admin-btn-admin-danger" value="削除" /> </td> </tr> </tbody> <tfoot> <tr> <td colSpan="5"> <input type="button" class="item-insert acms-admin-btn-admin" value="追加" /> </td> </tr> </tfoot> </table> <input type="hidden" name="@group_staff[]" value="group_staff_code" /> <input type="hidden" name="field[]" value="group_staff_code" /> <input type="hidden" name="group_staff_img:extension" value="media" /> <input type="hidden" name="@group_staff[]" value="group_staff_img" /> <input type="hidden" name="field[]" value="group_staff_img" /> <input type="hidden" name="@group_staff[]" value="group_staff_name" /> <input type="hidden" name="field[]" value="group_staff_name" /> <input type="hidden" name="field[]" value="@group_staff" />
これで、カスタムフィールドグループを使い自由に画像を追加できるようになりました。管理ページ > ブログ > カスタム設定 を開き「スタッフリスト」が追加されているのを確認して下さい。
インタビュー記事に使えそうな画像をブログのカスタムフィールドにいくつか登録しておきましょう(適当な人型の画像をご用意いただくか、下記URLなどの素材サイトから画像をダウンロードしてください)。また、各行に好きなコード名をふっておいて下さい。コード名は半角英数字が望ましいです。
今回のハンズオンの例では、かわいいフリー素材集 いらすとや さんの画像を使わせていただきました。
カスタムユニットの作成
次に、画像とテキストと吹き出しの向きを設定できるカスタムユニットを作成していきます。
入力側の設定
下記の入力用ソースを /themes/beginner2019/admin/entry/unit/extend.html に貼り付けます。指定したフォルダやファイルが無い場合は作成してください。
<!-- BEGIN custom_interview --> <table class="acms-admin-table-admin-edit"> <tr> <td colspan="2"> <!-- BEGIN_MODULE Blog_Field --> <!-- BEGIN group_staff:loop --> <div style="display:inline-block;"> <div style="margin-bottom:10px;" class="acms-admin-form-radio"> <input type="radio" name="interview_code\{id\}" value="{group_staff_code}" \{interview_code:checked#{group_staff_code}\} id="input-radio-interview_code-{group_staff_code}-\{id\}" class="acms-admin-btn-radio" /> <label for="input-radio-interview_code-{group_staff_code}-\{id\}"> <div style="width:70px;height:70px;"> <img class="js-focused-image" data-focus-x="{group_staff_img@focalX}" data-focus-y="{group_staff_img@focalY}" alt="{group_staff_img@alt}" src="%{MEDIA_ARCHIVES_DIR}{group_staff_img@path}[resizeImg(70)]" /> </div> <!-- BEGIN_IF [{group_staff_name}/nem] --> <p style="margin:5px 0 10px;font-size:10px;text-align:center;">{group_staff_name}</p> <!-- END_IF --> </label> </div> </div> <!-- END group_staff:loop --> <input type="hidden" name="unit\{id\}[]" value="interview_code\{id\}" /> <!-- END_MODULE Blog_Field --> </td> </tr> <tr> <th>吹き出しの向き</th> <td> <select name="interview_control{id}" class="acms-admin-form-width-sm"> <option value="right" {interview_control:selected#right}>右</option> <option value="left" {interview_control:selected#left}>左</option> </select> <input type="hidden" name="unit{id}[]" value="interview_control{id}" /> </td> </tr> <tr> <th>テキスト</th> <td> <textarea name="interview_text{id}" class="acms-admin-form-width-full">{interview_text}</textarea> <input type="hidden" name="unit{id}[]" value="interview_text{id}" /> </td> </tr> </table> <!-- END custom_interview -->
ここでのポイント!!
ポイント1
ブログのカスタムフィールド情報を表示させるために Blog Field モジュールを使用しています。
ポイント2
custom_interview ブロック内で Blog Field モジュールを展開しているため、custom_interview ブロックの変数が先に解決されないようにバックスラッシュでエスケープしています。
<input type="radio" name="interview_code\{id\}" value="{group_staff_code}" \{interview_code:checked#{group_staff_code}\} id="input-radio-interview_code-{group_staff_code}-\{id\}" class="acms-admin-btn-radio" /> <label for="input-radio-interview_code-{group_staff_code}-\{id\}">
ポイント3
interview_code の value には {group_staff_code}
を指定します。スタッフコードで一元管理し、ブログのカスタムフィールドを変更した時にエントリー側も変更されるようにしています。
<input type="radio" name="interview_code\{id\}" value="{group_staff_code}" \{interview_code:checked#{group_staff_code}\} id="input-radio-interview_code-{group_staff_code}-\{id\}" class="acms-admin-btn-radio" />
出力側の設定
下記出力用ソースを /themes/beginner2019/include/unit/extend.html に貼り付けてください。指定したフォルダやファイルが無い場合は作成してください。
<!-- BEGIN unit#custom_interview --> <div class="interview-{interview_control}-photo"> <!-- GET_Rendered id="{interview_code}" --> </div> <div class="interview-{interview_control}"><p>{interview_text}[escape|nl2br]</p></div> <!-- END unit#custom_interview -->
ここでのポイント!!
ポイント1
カスタムユニット内で Blog Field モジュールを呼び出すようなことはしません。カスタムユニット内で Blog Field モジュールを呼び出してしまうとユニットが追加されるたびにモジュールが動くため、重たいページになってしまいます。なので Set Rendered / Get Rendered を使ってユニットの軽量化をしていていきます。
<!-- GET_Rendered id="{interview_code}" -->
ポイント2
IDは {interview_code} を設定します。 {group_staff_code} で管理できるようにしたいため、スタッフコードが入っている {interview_code} をIDとして使用します。
ポイント3
吹き出しの向きによってスタイルを変更したいため、クラス名に変数 {interview_control} を含めます。CSSについては後ほど追記していきますが、.interview-right と .interview-left というセレクタ名でスタイルを分けていきます。
次に、下記 Blog_Field の出力用ソースを /themes/beginner2019/news/_entry.html のbodyタグ内に貼り付けてください。
※beginner2019 ではお知らせカテゴリーが用意されていますので、今回はそのお知らせカテゴリー内にインタビュー記事を作成します。
<!-- BEGIN_MODULE Blog_Field --> <!-- BEGIN group_staff:loop --> <!-- BEGIN_SetRendered id="{group_staff_code}" --> <div style="width:80px;height:80px"> <img class="js-focused-image" data-focus-x="{group_staff_img@focalX}" data-focus-y="{group_staff_img@focalY}" alt="{group_staff_img@alt}" src="%{MEDIA_ARCHIVES_DIR}{group_staff_img@path}[resizeImg(80)]" /> </div> <p class="interview-name">{group_staff_name}</p> <!-- END_SetRendered --> <!-- END group_staff:loop --> <!-- END_MODULE Blog_Field -->
ここでのポイント!!
ポイント1
カスタムユニット内で Blog_Field のループを何度も回して処理が重たくなるのを防ぐため、ユニットの外であらかじめモジュールを呼び出すようにしています。Set Rendered で変数化することで Get Rendered するだけで読み込めるようにしています。
ポイント2
SetRendered の ID には {group_staff_code} を指定し、スタッフコードを ID として使用します。
管理画面での設定
まず、管理画面上で custom_interview ユニットを登録します。 管理ページ > コンフィグ >デフォルトの[コンフィグ] > 編集設定 の「ユニット追加ボタン」にて [追加] ボタンをクリックし、モード:拡張、ユニット名:custom_interview 、ラベル:インタビュー、で新規ユニットを追加します。
次に、管理ページ > コンフィグ >デフォルトの[コンフィグ] > ユニット設定 の一番下にある[インタビュー]ボタンをクリックして追加したユニットが表示されるようにします。
スタイルの読み込み
/themes/beginner2019/include/head/link.html に下記スタイルコードを追加してください。
<style> /*-------------------- インタビューユニット ----------------------*/ .entry .interview-right, .entry .interview-left { display: block; position: relative; margin: 5px 10px 60px 10px; padding: 20px 30px; -webkit-border-radius: 20px; -moz-border-radius: 20px; border-radius: 20px; } .entry .interview-right p, .entry .interview-left p { margin: 0; } .entry .interview-left { background-color: #FFE4E6; margin-right: 100px; } .entry .interview-left:before { position: absolute; content: ""; display: inline-block; border: 8px solid transparent; border-left-color: #FFE4E6; right: -16px; } .entry .interview-left-photo { width: 80px; margin: 0 10px 0 0; height: 80px; float: right; position: relative; -webkit-border-radius: 40px; -moz-border-radius: 40px; border-radius: 40px; text-align: center; font-weight: 400; font-size: 12px; line-height: 1.9; } .entry .interview-right { background-color: #DEF7FF; margin-left: 100px; } .entry .interview-right:before { position: absolute; content: ""; display: inline-block; border: 8px solid transparent; border-right-color: #DEF7FF; left: -16px; } .entry .interview-right-photo { width: 80px; margin: 0 0 0 10px; height: 80px; float: left; position: relative; -webkit-border-radius: 40px; -moz-border-radius: 40px; border-radius: 40px; text-align: center; font-size: 12px; line-height: 16px; } .entry .interview-name { font-size: 10px; margin-top: 5px; } </style>
これでインタビュー記事を作成する準備は整いました。
インタビュー記事の作成
それでは実際にインタビュー記事のエントリーを作成してみましょう。「お知らせ」カテゴリーのテンプレートに Blog_Field の出力用ソース を貼り付けたかと思いますので、エントリー作成時には「お知らせ」カテゴリーを指定してください。上手く作成できましたか?
今回のハンズオンではブログのカスタムフィールドで登録した画像をカスタムユニットに使用することで動的なカスタムユニットを作成しました。インタビュー記事だけでなく他のカスタマイズにも使えるテクニックなので是非今後のサイト制作に役立ててください。