twig

このページでは、Twig テンプレートに関連する課題とその解決策を紹介しています。

最近のブログ記事5件をリストアップ

Problem:

読者が最近のブログの活動を見ることができるように、サイトのサイドバーに最近の 5 つのブログ記事を表示したいとします。

Solution:

単に /blog ページを見つけて、その子ページを取得し、日付の降順で並べ、最初の5つをリストで表示するようにするだけです。

<ul>
{% for post in page.find('/blog').children.order('date', 'desc').slice(0, 5) %}
    <li class="recent-posts">
        <strong><a href="{{ post.url }}">{{ post.title }}</a></strong>
    </li>
{% endfor %}
</ul>

ページ内で使用する場合は、ページのヘッダーに以下の設定を追加してください。

twig_first: true
process:
    twig: true

Add non modular navigation links

Problem:

モジュール化されていないページからのナビゲーションリンクを表示したい。

Solution
<div class="desktop-nav__navigation">
    {% for page in pages.children %}
        {% if page.visible %}
            {% set current_page = (page.active or page.activeChild) ? 'active' : '' %}
            <a class="desktop-nav__nav-link {{ current_page }}" href="{{ page.url }}">
                {{ page.menu }}
            </a>
        {% endif %}
    {% endfor %}
</div>

List the blog posts for the year

Problem:

この年に発生したすべてのブログ記事を表示したい。

Solution:

単に /blog ページを見つけて、その子ページを取得し、適切な dateRange() でフィルタリングして、日付の降順で並べるだけでよいのです。

<ul>
{% set this_year = "now"|date('Y') %}
{% for post in page.find('/blog').children.dateRange('01/01/' ~ this_year, '12/31/' ~ this_year).order('date', 'desc') %}
    <li class="recent-posts">
        <strong><a href="{{ post.url }}">{{ post.title }}</a></strong>
    </li>
{% endfor %}
</ul>

Displaying a translated month

Problem:

いくつかのページテンプレートでは、Twig の date フィルタが使用されていますが、これはロケール/多言語を扱いません。したがって、ページが英語以外の言語であっても、テンプレートが月の名前を表示することを選択すれば、英語で月を表示することができます。

Solution:

この問題には、2つの解決策があります。

First approach

1つ目は、Twig intlエクステンションを使用することです。

https://github.com/Perlkonig/grav-plugin-twig-extensions をインストールします。PHPのintlエクステンションがインストールされていることを確認します。

Twig テンプレートで、例えば (Antimatter テーマのように) {{ page.date|date("M") }} の代わりに {{ page.date|localizeddate('long', 'none', 'it', 'Europe/Rome', 'MMM') }} (ここにあなたの言語とタイムゾーンを追加します)とします。

Second approach

user/languages/ フォルダに en.yaml というエントリがあり、その中にいくつかの言語の翻訳が設定されているとします。

MONTHS_OF_THE_YEAR: [January, February, March, April, May, June, July, August, September, October, November, December]

そして、fr.yaml には、、、

MONTHS_OF_THE_YEAR: [Janvier, Février, Mars, Avril, Mai, Juin, Juillet, Août, Septembre, Octobre, Novembre, Décembre]

そして、あなたの Twig を反映されます。

<li>
    <a href='{{ post.url }}'><aside class="dates">{{ 'GRAV.MONTHS_OF_THE_YEAR'|ta(post.date|date('n') - 1) }} {{ post.date|date('d') }}</aside></a>
    <a href='{{ post.url }}'>{{ post.title }}</a>
</li>

これは Grav カスタム Twig フィルタ |ta を利用したもので、 Translate Array を意味します。 英語版では、次のような出力になります。

An Example Post  July 2015

そして、フランス語の場合、、、

Un exemple d’article Juillet 2015

ページの内容を要約せずに表示する

Problem:
ページ上部に要約を表示せず、ページの内容を表示したい。

Solution:

ページの内容から要約を削除するには、sliceフィルターを使用します。

{% set content = page.content|slice(page.summary|length) %}
{{ content|raw }}

Hiding the email to spam bots

Problem:

スパムロボットからメールを隠したい場合

Solution:

ページヘッダーでTwigの処理を有効にする。

process:
    twig: true

そして、safe_email Twig フィルタを使用します。

<a href="mailto:{{'your.email@server.com'|safe_email}}">
  Email me
</a>

Picking a random item from a translated array

Problem:

特定の言語で翻訳された配列からランダムに項目を選びたい。 これが動作するためには、ドキュメントで説明されているように、 多言語サイトの設定と構成 が完了していることが前提となります。

Solution:

また、このエントリーを含む en.yaml という user/languages/ フォルダーに、いくつかの言語の翻訳が設定されているとします。

FRUITS: [Banana, Cherry, Lemon, Lime, Strawberry, Raspberry]

そして、fr.yaml には、、、

FRUITS: [Banane, Cerise, Citron, Citron Vert, Fraise, Framboise]

Twig で利用可能になります。

{% set langobj  = grav['language'] %}
{% set curlang  = langobj.getLanguage() %}
{% set fruits   = langobj.getTranslation(curlang,'FRUITS',true) %}
<span data-ticker="{{ fruits|join(',') }}">{{ random(fruits) }}</span>

Displaying an image uploaded in a file field

Problem

カスタム blueprint に file フィールドを追加し、このフィールドに追加された画像を表示したいとします。

Solution

file` フィールドでは複数の画像をアップロードできるので、フロントマター内に 2 つのネストしたオブジェクトを生成します。最初のオブジェクトはアップロードされた画像のリストで、その中のネストしたオブジェクトは与えられた画像のプロパティ/バリューのグループです。

ユーザーに1つの画像だけを選択させたい場合は、選択された画像のプロパティを持つ単一のオブジェクトを保存する filepicker フィールドを使用する方が簡単であることに注意してください

一枚の画像がある場合、それをテンプレートに表示するには、次のようにします。

{{ page.media[header.yourfilefield|first.name] }}

ユーザーが複数の画像をアップロードできるようにした場合、Twigは次のようになります。

{% for imagesuploaded in page.header.yourfilefield %}
{{ page.media[imagesuploaded.name] }}
{% endfor %}

Displaying an image picked in a mediapicker field

Problem

カスタム ブループリントに mediapicker フィールドを追加し、選択した画像を表示するようにしました。

Solution

以下のように mediapicker フィールドを blueprint に追加することができます。

header.myimage:
  type: mediapicker
  folder: 'self@'
  label: Select a file
  preview_images: true

mediaapicker フィールドは、画像のパスを /home/background.jpg のような文字列で保存します。

この画像にページメディア機能でアクセスするためには、この文字列を分割して取得する必要があります。

  • この画像が保存されているページへのパス
  • 画像の名前を指定します。

以下のスニペットを使って、twig 経由で行うことができます。

{% set image_parts = pathinfo(header.myimage) %}
{% set image_basename = image_parts.basename %}
{% set image_page = image_parts.dirname == '.' ? page : page.find(image_parts.dirname) %}

{{ image_page.media[image_basename].html()|raw }}

Custom Twig Filter/Function

Problem

時には、PHP でしかできないロジックが Twig で必要になることがあります。そのため、最良の解決策は、カスタム Twig フィルタまたは関数を作成することです。 フィルタは通常、文字列に付加される形式です。関数は文字列や他の任意の変数型を取ることができます。関数は文字列や他の任意の変数型を取ることができます: custom_function("some string") しかし、基本的にこれらは非常に似ています。

また、"some string"|custom_filter('foo', 'bar') ように追加パラメータを渡すこともできます。関数のバリエーションは次のようになります: custom_function("some string", 'foo', 'bar').

この例では、文字列を受け取り、デリミタで区切られたチャンクに分割する数をカウントするシンプルな Twig フィルタを作成します。これは、クレジットカード番号やライセンスキーなどのようなものに特に便利です。

Solution

この追加機能を追加する最も良い方法は、カスタム・プラグインにロジックを追加することですが、テーマの php ファイルに追加することも選択肢の一つです。 この例では、わかりやすくするためにプラグインを使用します。 まず、プラグインをウィザード形式で簡単に作成するための devtools プラグインをインストールする必要があります。

bin/gpm install devtools

次に、新しいカスタムプラグインを作成し、プロンプトが表示されたら詳細を入力する必要があります。

bin/plugin devtools new-plugin

Enter Plugin Name: ACME Twig Filters
Enter Plugin Description: Plugin for custom Twig filters
Enter Developer Name: ACME, Inc.
Enter GitHub ID (can be blank):
Enter Developer Email: hello@acme.com

SUCCESS plugin ACME Twig Filters -> Created Successfully

Path: /Users/joe/grav/user/plugins/acme-twig-filters

デフォルトでは、新しいプラグインのためのこのスケルトンフレームワークは、 onPageContentRaw() イベントを通して、あなたのページにいくつかのダミーのテストを追加します。 まず、この機能を onTwigInitialized() イベントをリッスンするコードに置き換える必要があります。

public function onPluginsInitialized()
    {
        // Don't proceed if we are in the admin plugin
        if ($this->isAdmin()) {
            return;
        }

        // Enable the main event we are interested in
        $this->enable([
            'onTwigInitialized' => ['onTwigInitialized', 0]
        ]);
    }

    /**
     * @param Event $e
     */
    public function onTwigInitialized(Event $e)
    {

    }

onTwigInitialized() メソッドでフィルタを登録する必要があります。

/**
     * @param Event $e
     */
    public function onTwigInitialized(Event $e)
    {
        $this->grav['twig']->twig()->addFilter(
            new \Twig_SimpleFilter('chunker', [$this, 'chunkString'])
        );
    }

このメソッドの最初のパラメータには、フィルタ名として chunker を、ロジックが発生する PHP メソッドとして chunkString を登録します。 では、次にこれを作成する必要があります。

/**
     * Break a string up into chunks
     */
    public function chunkString($string, $chunksize = 4, $delimiter = '-')
    {
        return (trim(chunk_split($string, $chunksize, $delimiter), $delimiter));
    }

これで、Twigのテンプレートで試してみることができます。

{{ "ER27XV3OCCDPRJK5IVSDME6D6OT6QHK5"|chunker }}

以下のようになります。

ER27-XV3O-CCDP-RJK5-IVSD-ME6D-6OT6-QHK5

追加のパラメータを渡すことも可能です。

{{ "ER27XV3OCCDPRJK5IVSDME6D6OT6QHK5"|chunker(8, '|') }}

以下のようになります。

ER27XV3O|CCDPRJK5|IVSDME6D|6OT6QHK5

最後に、もしこれをフィルタだけでなく関数経由で利用したい場合は、onTwigInitialized() メソッドに同じ名前の Twig 関数を登録すればよいでしょう。

/**
     * @param Event $e
     */
    public function onTwigInitialized(Event $e)
    {
        $this->grav['twig']->twig()->addFilter(
            new \Twig_SimpleFilter('chunker', [$this, 'chunkString'])
        );
        $this->grav['twig']->twig()->addFunction(
            new \Twig_SimpleFunction('chunker', [$this, 'chunkString'])
        );
    }

これで、関数構文が使えるようになります。

{{ chunker("ER27XV3OCCDPRJK5IVSDME6D6OT6QHK5", 8, '|') }}

継承したテーマのベーステンプレートを拡張する

Problem

Sometimes you need to extend the base template itself. This might happen when there's no easy and obvious way to extend blocks already present in a template. Lets use Quark as an example for parent theme and you want to extend themes/quark/templates/partials/base.html.twig to your myTheme theme.

Solution

時には、ベースとなるテンプレートそのものを拡張する必要があります。これは、テンプレートに既に存在するブロックを拡張する簡単で明白な方法がない場合に起こります。Quarkを親テーマとして、themes/quark/templates/partials/base.html.twigmyTheme テーマに拡張する場合を考えてみましょう。

<?php
    namespace Grav\Theme;

    use Grav\Common\Grav;
    use Grav\Common\Theme;

    class MyTheme extends Quark {
        public static function getSubscribedEvents() {
            return [
                'onTwigLoader' => ['onTwigLoader', 10]
            ];
        }

        public function onTwigLoader() {
            parent::onTwigLoader();

            // add quark theme as namespace to twig
            $quark_path = Grav::instance()['locator']->findResource('themes://quark');
            $this->grav['twig']->addPath($quark_path . DIRECTORY_SEPARATOR . 'templates', 'quark');
        }
    }

これで themes/my-theme/templates/partials/base.html.twig で、Quarks のベーステンプレートをこのように拡張することができるようになりました。

{% extends '@quark/partials/base.html.twig' %}

    {% block header %}
    This is a new extended header.
    {% endblock %}