BLOG

ablogcms

@includeと@extendsを整理する

※これは a-blog cms Advent Calendar 2018 16日目の記事です。


サーバー移転の予定があるのでせっかくならその手順についてまとめようかと思ったのですが、私自身が苦戦していて間に合うか怪しくなってきた矢先、同カレンダー6日目を担当されていたさいとうみかこさんが「a-blog cms移転&SSL化をブロガーがやってみた顛末【さくら→エックスサーバー】」を書かれていたので、いっそのことそちらの記事で勉強させていただくことにしました。さいとうさんありがとうございます。


そのようなわけで今回は「@includeと@extendsを整理する」というテーマで書いていこうかと思います。


※追記:12日のうぇびんさんとテーマ被りしてますが日が近いということで目をつぶってください。。。


a-blog cmsの2大ファイル管理表記


a-blog cmsには2018/12現在、@includeと@extendsという2大ファイル管理表記があります。テンプレートを読む分にはどこから何のデータを参照しているのかそれとなくわかるのですが、いざ自分がその記法を使ってテンプレートを書こうとするとどの場面でどの記述が最適なのか迷ってしまうこともしばしば。


そこでまずは一度公式テーマファイルを開きながらそれらの役割について整理してみることにしました。


@includeについて


@includeは「テンプレート内に外部ファイルを読み込む」機能です。読み込みたいファイルのパスを@include記述内に書いて外部ファイル内の全ソースを1行に置き換えているようなイメージですね。モジュールやヘッダー、フッターなどのパーツごとに整理されることが多いです。


@includeについてはカレンダー8日目「新しい記法のインクルード文をつかってカスタムフィールドのソースを一括管理」でtamshowさんがお書きになっている通り、Ver. 2.8.0 から新しい記法が加わりました。これについて一番比較しやすいファイルはbeginner2018、site2018のそれぞれのtop.htmlです。


以下はbeginner2018から抜粋したソースです。


<!-- エントリーヘッドライン(トップ用) -->
@include("/include/entry/topHeadline.html")

<!-- エントリーサマリー -->
@include("/include/entry/topSummary.html")

これと同一の箇所がsite2018ではこのように表記されています。


<!-- エントリーヘッドライン(トップ用) -->
@include("/include/entry/headline.html", {"module_id": "top_headline"})

<!-- エントリーサマリー -->
@include("/include/entry/summary.html", {"module_id": "top_summary"})

さらにエントリーヘッドライン(トップ用)のインクルード元(/include/entry/topHeadline.html)に表記されているBEGIN_MODULEについても比較してみましょう。


begginer2018


<!-- BEGIN_MODULE Entry_Headline id="top_headline" -->

site2018 ​


<!-- BEGIN_MODULE Entry_Headline id="&lcub;&lcub;module_id&rcub;&rcub;" -->

エントリーサマリーのインクルード元(/include/entry/topSummary.html)でもこのような違いが見受けられます。


beginner2018


<!-- BEGIN_MODULE Entry_Summary id="top_summary" -->

site2018


<!-- BEGIN_MODULE Entry_Summary id="&lcub;&lcub;module_id&rcub;&rcub;" -->

見比べてみると、以前まではインクルード元に表記していたモジュールIDを、新しい記法ではインクルード先の@include内で変数として書き込んでいることがわかります。この表記ができるようになったことで、既に設置されたモジュールのIDを変更しなければいけない場合でも、1つのファイルから複数のモジュールIDを一元管理できるようになりました。以前までは@include表記でインクルード元のファイルのパスを調べてからそのファイルに移動して修正するということをしていたので、かなり時間短縮になるのではと思います。


また、ここではモジュールIDを例として扱っていますが、@include内では読み込み先のファイルで使われている変数なども書き込めるようになっています。同じモジュールを使って見出しや文言などを一部変更したいときなどは、@include内に記述することで値を上書きするということも可能です。


@extendsについて


@extendsは「テンプレートを継承する機能」です。継承という言葉の感覚が難しいですが、マルチブログ化と同じような階層の主従関係での取引をイメージするとわかりやすいかもしれません。(このように考えると、対する@includeはここでは並列関係になりそうですね。)


@extendsについて一番理解しやすいのは、テーマextend@beginner2018の_top.htmlかと思います。@extendsの他に@sectionや@parent、@endsectionなどの表記が出てきていますが、これら全て総括しての@extends機能です。


まずは_top.htmlの一番最初にある@extendsソースを見てみましょう。


_top.html


<!-- /_layouts/base.html テンプレートを継承 -->
@extends("/_layouts/base.html")

コメントにも書いてある通り、ここでは/_layouts/base.htmlを継承しているようです。では/_layouts/base.htmlを開いてみると、今度はあらゆるパーツにおいて@section〜@endsextion内に@includeがされています。どうやら@sectionと@endsextionは一定の範囲指定として使われているようです。下はheadタグ内から抜粋したものですが、@includeを使って/include/head/link.htmlを呼び出している部分が「head-link」というsectionで管理されています。


/_layouts/base.html


@section(head-link)
@include("/include/head/link.html")
@endsection

_top.htmlの@extendsは、これら/_layouts/base.html内で管理しているソースの全てを読み込んで出力する役割を担っています。つまりブラウザ上で_top.htmlを開いて表示されるものは、/_layouts/base.htmlのデータということです。


しかし実際には一字一句違わずに全く同じページが表示されるわけではありません。仮に全く同じページを出したい時には、_top.htmlには@extendsの記述のみ表記していれば良いのですが、_top.htmlを見てみるとこの一文の他にも様々なソースが含まれています。「基本的には同じレイアウトで表示したいけど、ページによってところどころ違うコンテンツを表示したい」ーこのような場合において、@sectionが役目を果たすのです。_top.html内に書かれた「head-link」sectionを例に見てみましょう。


_top.html


<!-- /_layouts/base.html の「section("head-link")」を上書き -->
@section("head-link")
@parent <!-- /_layouts/base.html の「section("head-link")」を挿入 -->
<link href="/js/slick/slick.css" rel="stylesheet">
@endsection

出力ソース


@include("/include/head/link.html") <!-- 「section("head-link")」の内容 -->
<link href="/js/slick/slick.css" rel="stylesheet"> <!-- _top_ext.htmlにおける追加分 -->

コメントには「/_layouts/base.htmlのsection("head-link")」を上書き」と書かれており、さらに@section内にある@parentは「/_layouts/base.htmlのsection("head-link")を挿入 」と説明があります。つまりこの@section内では、@parentである一定範囲についてベースの型を読み込ませながら、このページにのみ必要なlinkタグが追加されているのです。


さらに以下のように@section内から@patentを除くことで「全く違うコンテンツに置き換えることもできます。


_top.html


@section("head-link")
<link href="/js/slick/slick.css" rel="stylesheet">
@endsection

出力ソース


<link href="/js/slick/slick.css" rel="stylesheet">

@section内を空にすると、コンテンツ自体を非表示にすることも可能です。


_top.html


@section("head-link")
@endsection

出力ソース


<!-- なし -->

いかがでしょうか?このように@extendsの機能を使うと、@sectionによってソースの範囲を区切り、継承先のテンプレートで@sectionの内容についてパーツ単位で自由に編集することができます。元になっているソースを読み込むという点では@includeと同じですが、@sectionはその範囲を参照として追記・置き換え・非表示など情報の制御ができるので、上手く利用できればテンプレートの管理が非常に簡潔になりそうですね。


まとめ


@includeと@extendsの整理…と言いたいところですが、単語として@sectionやら@parentやらも新出しているので、ここではそれら全ての役割を振り返ってみます。


#@include,パーツごとに管理されているテンプレートを呼び出す
#@extends,あるファイルで基本のレイアウトを定め、その型を他のファイルで使えるようにする
#@section,レイアウトをページごとに編集できるようにするため、基本のレイアウトにおいて管理できる範囲を区切る
#@parent,@sectionで管理されているデフォルトのソースを呼び出す


個人的には


  • @includeはパーツ管理で@sectionは範囲の管理
  • @includeは編集不可で@sectionは編集可
  • @extendsは@sectionを使うための呪文みたいなもの

という感覚です。随分簡単になりましたが。


しかしこれらを活用してテンプレートを書こうとすると、やはりデザインを起こすことの重要性をしみじみと感じます。計画性のあるコーディングの指針となるものをスムーズに作れるように頑張りたいものです。



関連記事