このページでは、Twig テンプレートに関連する課題とその解決策を紹介しています。
読者が最近のブログの活動を見ることができるように、サイトのサイドバーに最近の 5 つのブログ記事を表示したいとします。
単に /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
モジュール化されていないページからのナビゲーションリンクを表示したい。
<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>
この年に発生したすべてのブログ記事を表示したい。
単に /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>
いくつかのページテンプレートでは、Twig の date
フィルタが使用されていますが、これはロケール/多言語を扱いません。したがって、ページが英語以外の言語であっても、テンプレートが月の名前を表示することを選択すれば、英語で月を表示することができます。
この問題には、2つの解決策があります。
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') }}
(ここにあなたの言語とタイムゾーンを追加します)とします。
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
Solution:
ページの内容から要約を削除するには、slice
フィルターを使用します。
{% set content = page.content|slice(page.summary|length) %}
{{ content|raw }}
スパムロボットからメールを隠したい場合
ページヘッダーでTwigの処理を有効にする。
process:
twig: true
そして、safe_email
Twig フィルタを使用します。
<a href="mailto:{{'your.email@server.com'|safe_email}}">
Email me
</a>
特定の言語で翻訳された配列からランダムに項目を選びたい。 これが動作するためには、ドキュメントで説明されているように、 多言語サイトの設定と構成 が完了していることが前提となります。
また、このエントリーを含む 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>
カスタム blueprint に file
フィールドを追加し、このフィールドに追加された画像を表示したいとします。
file` フィールドでは複数の画像をアップロードできるので、フロントマター内に 2 つのネストしたオブジェクトを生成します。最初のオブジェクトはアップロードされた画像のリストで、その中のネストしたオブジェクトは与えられた画像のプロパティ/バリューのグループです。
ユーザーに1つの画像だけを選択させたい場合は、選択された画像のプロパティを持つ単一のオブジェクトを保存する filepicker
フィールドを使用する方が簡単であることに注意してください
一枚の画像がある場合、それをテンプレートに表示するには、次のようにします。
{{ page.media[header.yourfilefield|first.name] }}
ユーザーが複数の画像をアップロードできるようにした場合、Twigは次のようになります。
{% for imagesuploaded in page.header.yourfilefield %}
{{ page.media[imagesuploaded.name] }}
{% endfor %}
カスタム ブループリントに mediapicker
フィールドを追加し、選択した画像を表示するようにしました。
以下のように 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 }}
時には、PHP でしかできないロジックが Twig で必要になることがあります。そのため、最良の解決策は、カスタム Twig フィルタまたは関数を作成することです。 フィルタは通常、文字列に付加される形式です。関数は文字列や他の任意の変数型を取ることができます。関数は文字列や他の任意の変数型を取ることができます: custom_function("some string")
しかし、基本的にこれらは非常に似ています。
また、"some string"|custom_filter('foo', 'bar')
ように追加パラメータを渡すこともできます。関数のバリエーションは次のようになります: custom_function("some string", 'foo', 'bar')
.
この例では、文字列を受け取り、デリミタで区切られたチャンクに分割する数をカウントするシンプルな Twig フィルタを作成します。これは、クレジットカード番号やライセンスキーなどのようなものに特に便利です。
この追加機能を追加する最も良い方法は、カスタム・プラグインにロジックを追加することですが、テーマの 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, '|') }}
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.
時には、ベースとなるテンプレートそのものを拡張する必要があります。これは、テンプレートに既に存在するブロックを拡張する簡単で明白な方法がない場合に起こります。Quarkを親テーマとして、themes/quark/templates/partials/base.html.twig
を myTheme
テーマに拡張する場合を考えてみましょう。
<?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 %}