EC-CUBE 4のテンプレートを開くと必ず出てくる {% extends %} と {% block %}。この2つが分かるとTwigの読み方が一気に楽になります。EC-CUBEに最初から入っているファイルを教材にして、継承とブロックの仕組みをまとめました。
{% extends %} は「土台にするテンプレートの指定」、{% block %} は「土台のどこを差し替えるかの指定」です。土台側に空の受け口を置いておき、各ページはそこへ入れる中身だけを書きます。
{% extends 'default_frame.twig' %}
{% block main %}
ここに書いた内容が、土台の {% block main %} の位置へ入る
{% endblock %}
この仕組みのおかげで、各ページに <html> や <head> を書かずに済んでいます。
本記事では、EC-CUBE(Symfony)で用いられるテンプレートエンジン『Twig』の基本となる、継承やブロックを中心にまとめています。EC-CUBE 4で用意されているTwigファイルを元に説明しているので、実際にコードを触りながら読むと理解が早いかもしれません。
【動作環境】EC-CUBEのバージョン:4.3.0 / サーバー:XServer
Twigの基本記法 早見表
この記事で扱う記法の一覧です。表の右上のボタンで表全体をコピーできます。
| 記法 | 役割 |
|---|---|
| {# コメント #} | コメントアウト。出力されない |
| {{ 値 }} | 変数や式の中身を出力する |
| {% extends ‘ファイル名’ %} | 指定したテンプレートを土台として継承する |
| {% block 名前 %} ~ {% endblock %} | 差し替え可能な区画を定義する |
| {% set 変数 = 値 %} | テンプレート内で変数を設定する |
| {% if 条件 %} ~ {% endif %} | 条件によって表示を切り替える |
| {% for 要素 in 配列 %} ~ {% endfor %} | 繰り返し表示する |
| {{ 値|trans }} | フィルターを通して加工した値を出力する |
Twigについては以下の記事にもまとめていますので、あわせてご覧ください。
- Twig まとめ(2) ~ if / for / set / with ~
- Twig まとめ(3) ~ trans / nl2br / escape / raw / price ~
- Twig まとめ(4) ~ マクロについて ~
デフォルトのTwigテンプレート(TOPページ)から、Twigを理解する
EC-CUBE 4で最初から用意されているTOPページのTwigテンプレート(index.twig)は以下のようになっています。コードは一部省略しています。EC-CUBE管理画面の「コンテンツ管理」→「ページ管理」から実物を見られます。
{#
This file is part of EC-CUBE
Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
http://www.ec-cube.co.jp/
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
#}
{% extends 'default_frame.twig' %}
{% set body_class = 'front_page' %}
{% block stylesheet %}
<style>
{# 〜略〜 #}
</style>
{% endblock %}
{% block javascript %}
<script>
{# 〜略〜 #}
</script>
{% endblock javascript %}
{% block main %}
<div class="ec-sliderRole">
<div class="main_visual">
<div class="item slick-slide"><img src="{{ asset('assets/img/top/img_hero_pc01.jpg') }}"></div>
<div class="item slick-slide"><img src="{{ asset('assets/img/top/img_hero_pc02.jpg') }}"></div>
<div class="item slick-slide"><img src="{{ asset('assets/img/top/img_hero_pc03.jpg') }}"></div>
</div>
</div>
{% endblock %}
後半のdivタグを除き、一般的なHTMLタグ(<html> や <body>)は書かれていません。一方で {# #} や {% %} で囲まれたTwig特有の記述が見られます。Twigテンプレートを使いこなすには、これらの記法を理解する必要があります。
{# ~ #} → コメントアウト
EC-CUBEのTwigテンプレートの冒頭数行には、{# #} で囲まれたコピーライトの記述がありますね。ここで囲まれた部分はコメントアウトで、書かれた内容は実行されず、出力もされません。
HTMLのコメントアウト(<!-- -->)とは書き方が違うので注意しましょう。
HTMLのコメントは「出力はされるがブラウザに表示されない」だけなので、ページのソースを見れば読めてしまいます。Twigのコメントは出力自体がされないため、開発用のメモを書くならこちらが安全です。
{% set %} → 変数設定
以下のように書くことで、テンプレート側で 変数 を設定できます。
{% set 変数 = 値 %}
先ほどのTOPページでは {% set body_class = 'front_page' %} と書かれており、bodyタグに付けるクラス名を変数として渡しています。詳しい内容は Twig まとめ(2) で解説しています。
{% extends %} → 継承
{% extends ファイル名 %} を最初に書いておくことで、指定したテンプレートを継承できます。継承とは、別で用意されているテンプレートを土台として読み込み、そこへ新しい内容を上書きして新たなテンプレートを作る機能です。
ここでは以下のような記述になっています。
{% extends 'default_frame.twig' %}
これは「default_frame.twig」というTwigテンプレートを継承し、新しいテンプレートを作ることを意味します。
継承とはどのような仕組みか?
「default_frame.twig」の中身を見ながら、継承の仕組みを見てみます。
まず「default_frame.twig」は src/Eccube/Resource/template の下に格納されています。他の記事で ファビコンの変更 や titleタグ の変更を行っている場合、app/template/default の下に「default_frame.twig」を新規作成している場合があります。その際はそちらを参照してください。
「default_frame.twig」の格納場所
「default_frame.twig」は以下のような構成になっています。コードが長いため一部を抜粋しています。
<!doctype html>
{#
~~~
#}
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
~~~
<title>{{ BaseInfo.shop_name }}</title>
~~~
<link rel="stylesheet" href="">
~~~
{% block stylesheet %}{% endblock %}
~~~
</head>
<body>
~~~
{% block main %}{% endblock %}
~~~
{% block javascript %}{% endblock %}
~~~
</body>
</html>
こちらのファイルでは <html>・<head>・<body> といった一般的なHTMLの記述になっていますね。titleタグやmetaタグも書かれています。
継承とは、この「default_frame.twig」をベースとし、継承先のTwigテンプレートの内容が反映されて新しいページが作られる、という仕組みです。TOPページのテンプレート「index.twig」はこれを継承しているため、<html> や <body> を書かなくてよいわけです。
TOPページに限らず、継承しているページはすべて同じように反映されます。レイアウトを統一でき、メンテナンスもしやすくなるというメリットがあります。
{% block %} → ブロック
Twigテンプレートでは、以下のようなブロックを用いた構文が使われます。
{% block 名前 %}
〜〜〜
{% endblock %}
Twigでは、上記で囲まれた部分を「指定した名前のブロック」として扱います。
ブロックの内容が、継承元のTwigに上書き(オーバーライド)される
TOPページ「index.twig」には {% block main %}{% endblock %} で囲まれた部分に、スライド画像を表示するimgタグが3つ書かれています。また、継承元の「default_frame.twig」にも {% block main %}{% endblock %} の記述があります。こちらの中身は空です。
このように書くと、
- 継承元「default_frame.twig」の
{% block main %}{% endblock %}に、 - 継承先「index.twig」の
{% block main %}{% endblock %}の内容が、
上書き(オーバーライド)されます。同様に {% block stylesheet %} や {% block javascript %} に書いた内容も、それぞれ同じ名前のブロックへ入ります。
ブロックは名前ごとに1対1で対応します。下の図で、記号がどこへ入るかを追ってみてください。
| ブロック名 | 継承先 index.twig に書いた中身 | 入る場所(継承元 default_frame.twig) |
|---|---|---|
| stylesheet | ○○○○○ | head内 |
| main | △△△△△ | body内の本文位置 |
| javascript | ××××× | body内の末尾 |
継承元「default_frame.twig」
<html>
<head>
<meta>
<title></title>
{% block stylesheet %}{% endblock %}
</head>
<body>
{% block main %}{% endblock %}
{% block javascript %}{% endblock %}
</body>
</html>
継承先「index.twig」
{% extends 'default_frame.twig' %}
{% block stylesheet %}
<style>
○○○○○
</style>
{% endblock %}
{% block main %}
<div class="ec-sliderRole">
△△△△△
</div>
{% endblock %}
{% block javascript %}
<script>
×××××
</script>
{% endblock %}
最終的に生成される内容
<html>
<head>
<meta>
<title></title>
<style>
○○○○○
</style>
</head>
<body>
<div class="ec-sliderRole">
△△△△△
</div>
<script>
×××××
</script>
</body>
</html>
EC-CUBEで用意されているページのほとんどには、最初に {% extends 'default_frame.twig' %} が書かれています。これをベースとすることで基本情報やレイアウトが統一され、各ページにはメインの内容だけを書けばよいためコードの可読性も上がります。
この仕組みを利用したカスタマイズ方法は、以下の記事で紹介しています。
2つ以上のテンプレートを継承できる?
できません。1つのテンプレートが継承できる土台は1つだけです。
{% extends %} を2回書くと、Twigは以下のエラーを出して停止します。
Multiple extends tags are forbidden.
2つ目が黙って無視されるのではなく、テンプレートの解析時点でエラーになる点に注意してください。EC-CUBE 4.3.0 は twig/twig 3.8.0 を使っており、このバージョンでは複数の {% extends %} が明確に禁止されています。
ただし、条件によって継承元を切り替えることは可能です。{% extends %} の記述自体は1つのまま、指定するファイル名を式にします。
{% extends is_mobile ? 'mobile_frame.twig' : 'default_frame.twig' %}
{% %} を使ったその他の記法
ここで紹介した以外にも、Twigテンプレートには {% %} というタグを使ってさまざまな機能が用意されています。
| タグ | 役割 |
|---|---|
| {% set %} | 変数設定 |
| {% if %} | 条件表示 |
| {% for %} | 繰り返し表示 |
| {% with %} | 変数の有効範囲を限定する |
| {% include %} | 別のテンプレートを読み込んで差し込む |
| {% macro %} | 繰り返し使う部品を関数のように定義する |
また、{{ 値|trans }} のように書くことで特殊な出力を行うフィルター機能もあります。それぞれ詳しくは以下の記事にて。
- Twig まとめ(2) ~ if / for / set / with ~
- Twig まとめ(3) ~ trans / nl2br / escape / raw / price ~
- Twig まとめ(4) ~ マクロについて ~

