カスタムユニットを動的化してみよう

この記事は公開日より4年以上経過しているため、現在の内容と異なる可能性があります。


通常カスタムユニットを変更しようと思った場合にはテンプレートを修正する必要が出てきます。ですがカスタムユニットの項目をカスタムフィールドで作ることによってテンプレートを触ることなくカスタムユニットの内容を変更できるようになります。

ハンズオン概要

今回は動的カスタムユニットを使ってインタビュー記事を作成していきます。カスタムユニットの完成イメージはこちらです。


カスタムユニット完成イメージ


今回動的化する箇所は画像になります。画像をブログのカスタムフィールドで登録できるようにし、その登録内容をカスタムユニットに表示できるように実装していきましょう。今回使用するテクニックは エスケープと 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 の出力用ソース を貼り付けたかと思いますので、エントリー作成時には「お知らせ」カテゴリーを指定してください。上手く作成できましたか?

今回のハンズオンではブログのカスタムフィールドで登録した画像をカスタムユニットに使用することで動的なカスタムユニットを作成しました。インタビュー記事だけでなく他のカスタマイズにも使えるテクニックなので是非今後のサイト制作に役立ててください。

同じタグ付けがされている記事