[Drupal] Viewsの外部設置フィルターをスタイリングする方法


1年半ぶりくらいにフロントエンドやったら死にかけたのでメモ。

Viewsの外部設置フィルターってなんや

これです。

テンプレートを変えずにクラスやIDを追加する

外部設置フィルターのスタイルを変えるお手軽な方法としては、hook_form_alterでCSSのクラスやIDを追加するというものがあります。現状ではフォームの入力部分とラベルのクラスとID、ラッパーを編集することができます。

function MY_MODULE_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {
  $view = $form_state->getStorage('view');
  if ($view['view']->id() === 'MY_VIEW') {

    // フォームの入力部分に属性を追加.
    $form['field_a']['#attributes']['class'][] = 'my-class';
    $form['field_a']['#attributes']['id'][] = 'my-id';

    // ラベルに属性を追加.
    $form['field_a']['#label_attributes']['class'][] = 'my-label-class';
    $form['field_a']['#label_attributes']['id'][] = 'my-label-id';

    // ラッパーを追加.
    $form['field_a']['#prefix'] = '<div class="my-wrapper-class">';
    $form['field_a']['#suffix'] = '</div>';
  }
}

テンプレートを編集する

HTMLの構造を根本的に変える必要がある場合は、テンプレートを編集します。外部設置フィルターの表示にはviews-exposed-form.html.twigという既存のテンプレートが使われているので、これを上書きします。

(ベーステーマがclassyの場合core/themes/classy/templates/views/views-exposed-form.html.twig)

こんなファイルです。

{#
/**
 * @file
 * Theme override of a views exposed form.
 *
 * Available variables:
 * - form: A render element representing the form.
 *
 * @see template_preprocess_views_exposed_form()
 */
#}
{% if q is not empty %}
  {#
    This ensures that, if clean URLs are off, the 'q' is added first,
    as a hidden form element, so that it shows up first in the POST URL.
  #}
{{ q }}
{% endif %}
{{ form }}

これをmytheme/template/views/views-exposed-form.html.twigにコピーして編集します。個々のフォーム要素は{{ form.FIELD_NAME }}で取得できます。(これを知らなくてめちゃくちゃハマった)

{#
/**
 * @file
 * Theme override of a views exposed form.
 *
 * Available variables:
 * - form: A render element representing the form.
 *
 * @see template_preprocess_views_exposed_form()
 */
#}
{% if q is not empty %}
  {#
    This ensures that, if clean URLs are off, the 'q' is added first,
    as a hidden form element, so that it shows up first in the POST URL.
  #}
{{ q }}
{% endif %}
<table>
  <tr>{{ form.field_a }}</tr>
  <tr>{{ form.field_b }}</tr>
</table>

特定のビューやディスプレイにだけ適用したい場合

上記のファイル名だと全ての外部設置フォームに適用されるので、特定の外部設置フォームにのみ適用したい場合は、テンプレート名を変えます。適当に命名はNGで、form#theme要素で設定されているものに変える必要があります。

テンプレートの中でformをデバッグするには、Develモジュールをインストールして

{{ dpm(form) }}

{{ kint(form) }}

と書くとブラウザで外部設置フォームを閲覧した際にformの中身が表示されます。

formの直下の#theme

 [#theme] => Array
        (
            [0] => views_exposed_form__MY_VIEW__page_1
            [1] => views_exposed_form__page_1
            [2] => views_exposed_form__MY_VIEW__page
            [3] => views_exposed_form__page
            [4] => views_exposed_form__MY_VIEW
            [5] => views_exposed_form
        )

のような感じで使えるテンプレート名がリストアップされているので、この中からちょうどいい粒度のものを使用します。(実際のファイル名は「_」を「-」にする必要があるので注意!)
例えばテンプレートのファイル名をviews-exposed-form--MY_VIEW--page-1にすると、「MY_VIEWというマシン名を持つビューのpage_1のディスプレイ」を閲覧したときのみ、そのテンプレートが適用されます。

#themeに定義されていないテンプレート名を使いたいとき

権限によってテンプレートを変えるなど(?)#themeに定義されているテンプレートの粒度では間に合わない!という場合はhook_theme_suggestions_HOOK_alterでテンプレート名を追加することもできます。

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 */
function MYTHEME_theme_suggestions_views_exposed_form_alter(&$suggestions, &$vars, $hook) {
  //特定の条件下でviews-exposed-form--custom.html.twigを読み込むようにする
  if (条件) {
    $suggestions[] = 'views_exposed_form__custom'; //「-」は全て「_」に変換する点に注意
  }
}