チュートリアル:entries.tplテンプレートの編集
この長ったらしいチュートリアルはフォーラムのスレッド http://www.s9y.org/forums/viewtopic.php?t=4013 からの抜粋です。
最初の質問はこれでした:
質問
私が作ったcarl blueテーマを他のユーザーがカスタマイズするのを手伝っているところです。
私たちは自作のカスタムバージョンではなく、標準の方法に戻ってentries.tplを変更することにしました。
それで今はもちろん、同一日に投稿されたエントリは全てひとまとめに分類されているように見えます。
ここは完璧なのですが、これらのエントリ間だけにセパレータを加えることが可能なのか疑問を感じました。
例えば、日付でグループを分けるのではなく、同一日のエントリ毎を分けるということです。
返事 (Judebertさん)
それが可能かどうか、わかりやすい英語で説明してみたいと思います。
頭痛がしていない時に遠慮なく読んでみてください。
Smartyの全てについて説明を始めることもできますが、差し当たり話題に近いところに留めておきます。
また、あまり経験の無い人が読んでいるかもしれないので、説明はかなり基本的なものとするつもりです。
まず初めに、問題点をはっきりさせましょう。
グループ化されたエントリの間にセパレータが欲しいわけです、こんな感じで。
日付 記事
記事
記事 日付 記事
...などなど。
このパターンを見ると、最後のエントリを除く各エントリの直下に分割線があるのがわかります。
さて、記事というのは、タイトル・本文・フッタなどのたくさんの部品から成り立っています。(ほとんど)全てのパーツを囲っているdivすらあります。
しかしながら、話を簡単にするために、実際には個々のセパレータを加えることにしましょう。
このために設計されたHTMLのタグは <HR> です。
画面に水平線 (Horizontal Rule) を表示させます。
CSSは必要ですらありません!
HTMLを生成する部分はテンプレートですから、私たちはテンプレートを変更する必要があります。
知っての通り entries.tpl がエントリを生成する部分です (だからこういうファイル名となっています)。
ではそこに行きましょう。
Smartyは {} の中に注意を向けます。
他のものは全て単なるHTMLです。
特に気をつける必要の無い部分を全て削除すれば、こんな感じに見えます:
{foreach from=$entries item="dategroup"}
<div class="serendipity_Entry_Date">
{if $dategroup.is_sticky}
<h3 class="serendipity_date">{$CONST.STICKY_POSTINGS}</h3>
{else}
<h3 class="serendipity_date">
{$dategroup.date|@formatTime:DATE_FORMAT_ENTRY}</h3>
{/if}
{foreach from=$dategroup.entries item="entry"}
<h4 class="serendipity_title">
<a href="{$entry.link}">{$entry.title}</a></h4>
<div class="serendipity_entry
serendipity_entry_author_{$entry.author|@makeFilename}
{if $entry.is_entry_owner}serendipity_entry_author_self{/if}">
... entry stuff ...
</div>
{/foreach}
... other stuff ...
</div>
{foreachelse}
{if not $plugin_clean_page}
{$CONST.NO_ENTRIES_TO_PRINT}
{/if}
{/foreach}
最初の {foreach} が $entries 内の全アイテムをループして走査します。
$entries はSerendipityが私たちのために書き込んだ投稿記事の配列です。
Serendipityは日付に準じて記事をグループ化するので、Smartyは各日付毎に一度ループ走査しています。
各日付を dategroup と呼ぶことにします。
detegroup ごとにdivを生成し、次に日付を (またはもし記事がsticky groupの場合、スティッキ投稿と) 表示します。
dategroups には複数の記事を保持しているかもしれません。
次の {foreach} は entry と呼ばれる各記事をひとつひとつ走査しにいきます。
いくつかのクラスを伴ったdivタグを生成し、エントリの中身を表示し、最終的にループの終わり ({/foreach}) にたどりつきます。
そして、他のエントリを走査するために元に帰ってきます。
もし各記事の終わり部分に何かを挿入したいのなら、こここそがその挿入箇所です。
入力したいかなるHTMLも各記事毎にインクルードされるはずです。
ということで、ここに <hr> を挿入してみればセパレータを得られるはずです。
コードの抜粋です:
... entry stuff ...
</div>
<hr>
{/foreach}
... comment stuff ...
</div>
{foreachelse}
これで動きましたが、全ての記事の後に <hr> を入れたのでこんな風に見えてしまいます。
日付 記事
記事
日付 記事
最後の記事の後の余分なセパレータがわかりますか? これは不要です。取り除いていきましょう。
私たちが既に得たコードを見てみれば {if} ステートメントがあるのがわかると思います。
もし日付がスティッキ日付だったなら、STICKY_POSTINGS 文字列を含んだ <H3> タグを作ります。そうでないなら、日付を含んだ <H3> タグを作ります。
もし閲覧者が記事の著者だった場合は、serendipity_entry_author_self クラスを追加するために {if} も使います。相当抜け目が無いですよ。
その記事が最初のものであるかどうかを知らせるために、何らかの方法で独自の {if} を追加しなければいけません。 もし記事がループ走査中の最初のものでなかった場合には、セパレータを加える必要があります。記事が一つだけだった場合は、自動的にループの最初となるので、セパレータはスキップさせます。
幸いにもSmartyにはまさにこの機能が備わっています。
ただ、あいにくこの機能は entry か dategroup かを確認できるものではありません。
{foreach} で確認する必要があります。
その点をお話しするために、そして別の {foreach} と間違えないよう、ユニークな名前を与える必要があります。
もちろん、Smartyにはこの機能もあります。
さて、今やるべきことは二つあります:
- 自作の {foreach} に名前をつける。
- もし1回目のループ走査だったら自作の {foreach} に問い合わせる必要があり、該当する場合はセパレータをスキップする。
十分簡単です。これが自作の foreach に名前をつける方法です:
{foreach name="dategroup" from=$dategroup.entries item="entry"}
単に name 属性を追加しただけです。
どんな名前でも大丈夫ですが、dategroup がわかりやすいと思われます。
実際に作っていきます。
{foreach} のフルネームは $smarty.foreach.dategroup となります。
さて、グループの最初のエントリの位置にいるかどうか確認する必要があります。
これは自作 foreach の first 属性を確認するのと同じく簡単です。
このようになります:
{if $smarty.foreach.dategroup.first}
<!-- No separator for this! -->
{else}
<hr>
{/if}
これで動きます。
もちろん、もっと簡単な方法もあります。
ループの最初ではない時にだけセパレータが欲しいので、自作の {if} に not を追加し、{else} 全体を取り除くのです。
{if not $smarty.foreach.dategroup.first}
<hr>
{/if}
コードは小さい方がより良いものです。なぜなら、その方が速いからです(厳密には、このケースでの話しで、ええと、、、ここではそう主張します…)。
もちろん <hr> 以外のHTMLタグを使うことも可能です。 しっかり組んだ div を加えることも、span でも 画像でも何でも追加可能です。 CSSを理解しているのなら、割り当てた div に特別なクラスを与えてやれば、ボーダーや大き目のマージンや異なった色やその他色々な設定を追加できます。 ただ、ここで説明するには既に長くなってしまいました。
締めの言葉
上述のフォーラムスレッドではもう少し色々な注意点を読むことができます。
この解説、そしてそれをこのWiki (※訳者注:原文はWikiで管理されておりますが、ここはWikiではありません) に掲載できたことについて、Judebert氏に大いに感謝します。