こんにちは。早いもので2018年もあと2ヶ月ちょっとですね。

最近twigテンプレートを触る機会が多いのですが、もどかしくなること結構ありませんか。

このデータを出力したいのに標準で使用できる変数には含まれていなかったり、ちょっとデータを加工したいのに意外と面倒だったり…。

そんなとき、twigの開発がスムーズになるよう手助けしてくれるモジュールがあるのをご存知でしょうか。
その名もTwig Tweakモジュールです。

Twig Tweakモジュール

Twig Tweakモジュールはtwigの拡張関数やフィルターを提供してくれるモジュールです。いつも通りインストールするだけで、特別な設定等は不要です。

このブログを公開した時点の最新バージョンは8.x-2.1です。
8.x-1系もありますが、1系と2系ではAPIが異なる部分があり、1系から2系に移行するにはtwigの修正がともないます。これから使われる方は2系を選択することをおすすめします。

それでは実際にどのような関数、フィルターが用意されているのかご紹介します。 なお、今回ご紹介する内容はこちらのCheat sheetを参考に作成しました。仕様についてもっと詳しく知りたい方は、Cheat sheetや実際のコードを見ていただくと良いかと思います。

8.x-2.1時点の関数

drupal_view

Viewsを出力するための関数です。内部的にはviews_embed_viewを実行しています。

{# 第3引数以降はViewsの引数として渡したい値です(省略可 #}
{{ drupal_view('viewの内部名称', 'display_id', foo, bar) }}

drupal_view_result

Viewsの結果を取得するための関数です。内部的にはviews_get_view_resultを実行しています。戻り値はResultRowクラスの配列で、結果がない場合は空の配列です。結果の有無をチェックする時に重宝しそうです。

{# 引数はdrupal_viewと同じ #}
{% set result = drupal_view_result('viewの内部名称', 'display_id', foo, bar) %}

drupal_block

ブロックを出力するための関数です。が、ブロックの種別によって実際に使用する関数が異なるようなので、詳しくはこちらをご覧ください

{{ drupal_block('search_form_block') }}

{# wrapperなし #}
{{ drupal_block('search_form_block', wrapper=FALSE) }}

drupal_region

リージョンを出力します。第2引数にテーマを指定することが可能です(省略可)。

{{ drupal_region('region名', 'umi_sample') }}

drupal_entity

エンティティを出力します。ビューモードや言語も指定できます。

{# カスタムブロック #}
{{ drupal_entity('block_content', 1) }}

{# ノード #}
{{ drupal_entity('node', 3, 'teaser') }}

drupal_entity_form

エンティティの追加フォームまたは編集フォームを出力します。

{# ノードの編集フォームを出力 #}
{{ drupal_entity_form('node', 'nidの値') }}

{# 記事コンテンツの追加フォームを出力 #}
{{ drupal_entity_form('node', 'values={type: 'article'}') }}

drupal_field

特定のフィールドだけを出力します。こちらもdrupal_entity同様、ビューモードや言語を指定できます。

{{ drupal_field('field_image', 'node', 4, 'teaser') }}

drupal_menu

メニューを出力します。levelや深さを指定することも可能です。

{{ drupal_menu('main', 2, 3, TRUE) }}

drupal_form

フォームを出力します。ソースを確認したところ引数名は$form_idなのですが、内部的にはこちらの関数を実行しているようなので、実際はFormInterfaceを実装したクラス名またはそのクラスのインスタンスを指定する必要があるようです。第2引数以降はフォームに渡す引数を指定できます。

{# スラッシュはエスケープしてください #}
{{ drupal_form('Drupal\\user\\Form\\UserLoginForm') }}

drupal_image

画像を出力します。画像の指定はURIのほか、FID、UUIDでも可能です。

{{ drupal_image('public://sample.jpg', NULL, {alt: 'サンプル画像'}) }}

drupal_token

トークンの値を出力します。

{{ drupal_token('site:title') }}

使用するデータを指定することも可能です

{{ drupal_token('node:title', {node: node}) }}

drupal_config

configの値を出力します。引数にはconfigの名前と取得したいキー名を指定します。

{{ drupal_config('system.maintenance', 'message') }}

drupal_dump / dd

デバッグ用の関数です

{{ dd(variables) }}

drupal_title

タイトルを出力します

{{ drupal_title() }}

drupal_url

URLを出力します。Drupalコアにもurl関数がありますが、コアの関数がルートを指定するのに対し、drupal_urlはパスを指定します。第2引数にはUrl::fromUserInputで使用可能なオプションが指定できます

{{ drupal_url('node/5', {absolute: TRUE}) }}

drupal_link

リンクを出力します。第2引数以降はdrupal_urlと同様です

{{ drupal_link('リンクのテキスト', 'node/5', {attributes: {target: '_blank'}) }}

drupal_messages

Drupalのステータスメッセージをブロックのラッパー要素なしで出力します。

{{ drupal_messages() }}

drupal_breadcrumb

パンくずリストをブロックのラッパー要素なしで出力します。

{{ drupal_breadcrumb() }}

drupal_breakpoint

Xdebugのブレークポイントをtwigに置けるらしいです。(Xdebug使ってないので、気になる方はお試しください)

{{ drupal_breakpoint() }}

8.x-2.1時点のフィルター

token_replace

指定した文字列内に含まれるトークンを、対応する値に置換します。drupal_tokenと似ていますが、残念ながらtoken_replaceはデータを指定することはできないようです

{{ '<h1>[site:name]</h1><div>[site:slogan]</div>'|token_replace }}

php

非推奨ですがphpの実行もできます。極力使わない方が良いでしょう...デフォルトでは無効になっているので、どうしても使用したい場合はsettings.phpに

$settings['twig_tweak_enable_php_filter'] = TRUE;

を追加してください。

{{ 'return date("Y-m-d");'|php }}

transliterate

翻字(日本語などをアルファベットに変換すること)を行います。

{# 結果は、konnichiha です #}
{{ 'こんにちは'|transliterate }}

check_markup

指定した文字列をテキストフォーマットに適合した形に変換します。

{{ '<b>bold</b><strong>strong</strong>'|check_markup('restricted_html') }}

truncate

文字の切り詰めを行います。内部的にはUnicode::truncateを実行しており、引数も同じです。

{# 結果は、あいうえおかきくけこさ... です #}
{{ 'あいうえおかきくけこさしすせそ'|truncate(12, FALSE, '...') }}

with

Drupalコアのtwig関数であるwithoutとは逆に、レンダリング配列に要素を追加(または上書き)します

{{ content.field_image|with('#title', 'Override') }}

view

エンティティやフィールドのオブジェクトをレンダリング配列に変換します。ビューモードなどを指定することも可能です。

{{ node|view('teaser') }}

{{ node.field_image|view }}

Twig拡張機能はViewsでも使えるため便利

Twig Tweakモジュールで拡張された関数やフィルターは、もちろんViewsでも使用することができます。

例として、親子関係をもつコンテンツのケースを考えます。親の一覧があり、各行にはその親にひもづく子コンテンツを表示するような場合です。

子ビューは、コンテキスチュアルフィルターに親のIDを受け取り、その値によって絞り込むようにしておきます。

親ビューでは、非表示のフィールドとしてノードIDを追加します。そして、独自のテキストフィールドを追加し、

{{ drupal_view('子ビューの名前', '子ビューのdisplay id', nid) }}

とすると、それだけで各行に子ビューを表示することができます。

今まで同じことをしようとすると、親ビューと子ビューを作成した後に

  1. template_preprocess_views_view_fields等で入れ子したいViewsを取得し、$variablesに追加
  2. views-view-fields--xxx.html.twigファイルを追加し、先ほど追加したViewsを埋め込む

という2段階が必要でした。
しかしTwig Tweakモジュールを導入することでViewsの設定画面だけで完了し、コード量やテンプレートファイルも削減できるようになります。

まとめ

どのプロジェクトでも必ずしも必要というわけではありませんが、複雑なレイアウトのページが多いサイトなどテンプレート開発を避けられない場合は、痒いところに手が届くモジュールではないかと思います。
テンプレート開発がしんどいなあと感じた場合はぜひお試しください!