a-blog cmsのカスタムフィールドを動的化して、データベースのように扱う
この記事は、a-blog cms Advent Calendar 2022 の11日目の記事です。今回は、カスタムフィールドの動的化についてです。
「カスタムフィールドを動的化する」とは
a-blog cmsではカスタムフィールドを繰り返し追加できるカスタムフィールドグループがあります。カスタムフィールドグループのテンプレートタグをエスケープをすることで、カスタムフィールドの項目を管理画面から管理することができます。
図の例ではブログ管理では果物の名前を登録して、エントリー投稿画面では果物の名前を選択できるようにしています。(今回はブログ管理ですが、モジュールIDで管理するのもおすすめです) 表示画面では選択した果物の名前を表示しています。これを実装するにはカスタムフィールドメーカーを使いながら、次のようなコードを作成します。
ブログ管理
<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 acms-admin-admin-config-table-action">削除</th>
</tr>
</thead>
<tbody>
<!-- BEGIN master_fruit: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="master_fruit_name[]" value="{master_fruit_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 master_fruit: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="master_fruit_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="3">
<input type="button" class="item-insert acms-admin-btn-admin" value="追加" />
</td>
</tr>
</tfoot>
</table>
<input type="hidden" name="@master_fruit[]" value="master_fruit_name" />
<input type="hidden" name="field[]" value="master_fruit_name" />
<input type="hidden" name="field[]" value="@master_fruit" />
エントリー投稿
<!-- BEGIN_MODULE Blog_Field -->
<!-- BEGIN master_fruit:loop -->
<div class="acms-admin-form-checkbox">
<input type="checkbox" name="entry_fruit[]" value="{master_fruit_name}" <!-- BEGIN\ entry_fruit:loop --><!-- BEGIN_IF [\{entry_fruit\}/eq/{master_fruit_name}] -->checked<!-- END_IF --><!-- END\ entry_fruit:loop --> id="input-checkbox-entry_fruit-{master_fruit_name}" />
<label for="input-checkbox-entry_fruit-{master_fruit_name}">
<i class="acms-admin-ico-checkbox"></i>{master_fruit_name}</label>
</div>
<!-- END master_fruit:loop -->
<!-- END_MODULE Blog_Field -->
<input type="hidden" name="field[]" value="entry_fruit" />
<a href="/bid/%{BID}/admin/blog_edit/#acms_custom" class="acms-admin-btn">果物の編集</a>
表示画面
<!-- BEGIN entry_fruit:loop --><!-- BEGIN glue -->、<!-- END glue -->{entry_fruit}<!-- END entry_fruit:loop -->
「カスタムフィールドの動的化」の問題点と解決方法
ただし、このときにはエントリーには果物の名前しか登録されていないため、表示画面で果物の名前以外を出すことができません。この場合、表示画面でIFブロックを使うことで解消することができます。
<!-- BEGIN entry_fruit:loop -->
<!-- BEGIN_IF [{entry_fruit}/eq/りんご] -->
<img src="/images/ringo.jpg" alt="" />
<!-- ELSE_IF [{entry_fruit}/eq/みかん] -->
<img src="/images/mikan.jpg" alt="" />
<!-- ELSE_IF [{entry_fruit}/eq/ばなな] -->
<img src="/images/banana.jpg" alt="" />
<!-- END_IF -->
<!-- END entry_fruit:loop -->
ただ、せっかく管理画面で変更できるようにしたのに、IFブロックを書くのでは管理画面の操作だけで完結しないですよね。そこで、表示画面でモジュールをエスケープすることで解消することができます。
<!-- BEGIN entry_fruit:loop -->
<!-- BEGIN_MODULE\ Blog_Field -->
<!-- BEGIN\ master_fruit:loop -->
<!-- BEGIN_IF [{entry_fruit}/eq/\{master_fruit_name\}] -->
<img src="%{MEDIA_ARCHIVES_DIR}\{master_fruit_image@path\}" alt="" />
<!-- END_IF -->
<!-- END\ master_fruit:loop -->
<!-- END_MODULE\ Blog_Field -->
<!-- END entry_fruit:loop -->
複数のカスタムフィールドグループを使用する
では、カスタムフィールドグループの値をもとに、別のカスタムフィールドグループの値を参照したくなった場合はどうでしょうか。例えば、果物の問い合わせ先を登録して、別で管理している問い合わせ先の情報を参照する場合などです。
a-blog cmsではエスケープをさらにエスケープすることはできませんので、例えば次のようなコードは動きません。
<!-- BEGIN entry_fruit:loop -->
<!-- BEGIN_MODULE\ Blog_Field -->
<!-- BEGIN\ master_fruit:loop -->
<!-- BEGIN_IF [{entry_fruit}/eq/\{master_fruit_name\}] -->
<!-- BEGIN_MODULE\\ Blog_Field -->
<!-- BEGIN\\ master_contact:loop -->
<!-- BEGIN_IF [\{master_fruit_contact\}/eq/\\{master_contact_name\\}] -->
問い合わせ先: \\{master_contact_manager\\}
<!-- END_IF -->
<!-- END\\ master_contact:loop -->
<!-- END_MODULE\\ Blog_Field -->
<!-- END_IF -->
<!-- END\ master_fruit:loop -->
<!-- END_MODULE\ Blog_Field -->
<!-- END entry_fruit:loop -->
この場合、以下のような校正オプションを追加することで解消することができます。校正オプションの引数に紐付けたいフィールドグループの変数名、取り出したいフィールドグループの変数名を指定します。
/extension/acms/Corrector.php
/**
* cfg_value
* カスタムフィールドグループの値をキーにして、同じカスタムフィールドの値を取得する
*/
public function cfg_value($txt, $args = array())
{
$field_group_key = isset($args[0]) ? $args[0] : '';
$value_key = isset($args[1]) ? $args[1] : '';
if ($field_group_key && $value_key) {
$DB = DB::singleton(dsn());
// ソート番号を取得
$SQL = SQL::newSelect('field');
$SQL->addSelect('field_sort');
$SQL->addWhereOpr('field_key', $field_group_key, '=');
$SQL->addWhereOpr('field_value', $txt, '=');
$sort = $DB->query($SQL->get(dsn()), 'one');
if ($sort) {
// ソート番号から値を返す
$SQL = SQL::newSelect('field');
$SQL->addSelect('field_value');
$SQL->addWhereOpr('field_key', $value_key, '=');
$SQL->addWhereOpr('field_sort', $sort, '=');
$txt = $DB->query($SQL->get(dsn()), 'one');
}
}
return $txt;
}
表示画面(エスケープを使用する場合)
<!-- BEGIN entry_fruit:loop -->
<!-- BEGIN_MODULE\ Blog_Field -->
<!-- BEGIN\ master_fruit:loop -->
<!-- BEGIN_IF [{entry_fruit}/eq/\{master_fruit_name\}] -->
\{master_fruit_contact\}[cfg_value('master_contact_name', 'master_contact_manager')]
<!-- END_IF -->
<!-- END\ master_fruit:loop -->
<!-- END_MODULE\ Blog_Field -->
<!-- END entry_fruit:loop -->
表示画面(エスケープを使用しない場合)
校正オプションなので、校正オプション側で二重にすることが可能です。
<!-- BEGIN entry_fruit:loop -->
{entry_fruit}[cfg_value('master_fruit_name', 'master_fruit_contact')|cfg_value('master_contact_name', 'master_contact_manager')]
<!-- END entry_fruit:loop -->
以上、このようにすることでa-blog cmsのカスタムフィールドグループを使って、リレーショナルデータベースのようなことを実現することができます。設計の幅が広がると思いますので、参考になれば幸いです。
コメント