はじめに
ヘルプセンターのテーマは、編集可能なページテンプレートの集まりです。テンプレートとは、ヘルプセンター内の各種ページタイプのレイアウトを定義するものです。たとえば、ナレッジベースの記事用のテンプレートや、リクエストのリスト用のテンプレートなどがあります。
各テンプレートは、HTMLマークアップと、Handlebarsなどの式によって構成されます。これらは、テンプレート内で二重の波かっこで囲んで表されます。Handlebarsは、シンプルなテンプレート化エンジンです。これにより、設計時ではなく、レンダリング時にページ内にコンテンツを挿入したり、コンテンツを操作できるようになります。
ヘルプセンター内のテンプレート化言語はCurlybarsと呼ばれ、Handlebars言語の大部分を実装しています。このガイドでは、Curlybars言語を使用してヘルプセンターのページをカスタマイズする方法を説明します。
ヘルプセンターでは、ヘルパーと所定のプロパティを使用して、コンテンツをカスタマイズできます。プロパティには、すべてのヘルプセンターページ上で共有され使用されるものと、ページ固有のものがあります。
例
{{#each comments}}
<li class="comment" id="{{comment_id}}">
<div class="comment-avatar {{#if author.agent}} comment-avatar-agent {{/if}}">
<img src="{{author.avatar_url}}" alt="Avatar" />
</div>
<div class="comment-container">
<header class="comment-header">
<strong class="comment-author">
{{author.name}}
</strong>
</header>
</div>
</li>
{{/each}}
この例は、ページにコメントを残したユーザーのリストを生成します。each
ヘルパーは、ページのcomments
プロパティ内のすべての値を反復処理します。各コメントについて、author.avatar_url
プロパティとauthor.name
プロパティの値がHTML内に挿入されます。
テンプレートの基本
このセクションでは、テンプレートの作成に必要な基本事項について説明します。詳細については、developer.zendesk.comで「Help Center Templates(ヘルプセンターのテンプレート)」を参照してください。
Curlybarsテンプレートは、そのままレンダリングされるverbatimテキストと、Curlybars式という2つの要素で構成されます。つまり、空のテンプレートも有効なテンプレートであり、テキストのみが含まれるテンプレートも有効なテンプレートです。以下は、有効なテンプレートの例です。
<h1>Article</h1>
<p>Some details on the article</p>
もちろん、ヘルプセンターテンプレートがverbatimテキストしかサポートしないとしたら、レンダリング時に十分なカスタマイズはできません。テンプレートのロジックを追加するには、Curlybars式が必要です。この式は、二重の波かっこ({{
および}}
)で囲んで表します。
前述の例にテンプレートのロジックを追加するには、テンプレートを次のように編集します。
<h1>Article</h1>
<p>Some details on the article</p>
{{article.author.name}}
次のセクションでは、必要に応じてテンプレートに変更を加えるために、さまざまな式を記述する方法について説明します。
なお、波かっこのペアを別の波かっこのペアに入れ子にした場合、そのシンタックスは無効です。たとえば、以下のように記述することはできません。
<h1>Article</h1>
<p>Some details on the article</p>
{{ {{ ... }} }}
コメント
状況によって、レンダリングページに表示されないメモをテンプレート内に書いておくと便利な場合があります。Curlybarsでこれを行うには、{{! ... }}
のように、開き波かっこの直後(スペース不要)に感嘆符を挿入してコメントを追加します。このシンタックスを使用して、以下の例のようにコードコメントを挿入できます。
{{!
This template aims to
show details of an article
}}
<h1>Article</h1>
<p>Some details on the article</p>
レンダリング時には、このページはブラウザに以下のように表示されます。
<h1>Article</h1>
<p>Some details on the article</p>
このように、コメントとして挿入したテキストはすべて無視されるため、テンプレート開発時にコメントを使用すると非常に便利です。たとえば、チェックやデバッグなどを行うときに、一部のコードをコメントアウトしたい場合があります。
コメントのブロック
残念ながら、上述のコメントシンタックスは、Curlybarsコードのコメントアウトには使用できません。Curlybarsコードをコメントアウトするには、{{!-- ... ---}}
のように、開き波かっこの直後(スペース不要)に感嘆符を挿入してコメントを追加します。このシンタックスによるコメントは、複数行にわたって使用でき、コードを効果的にコメントアウトできます。例:
{{!
This template aims to
show details of an article
}}
<h1>Article</h1>
<p>Some details on the article</p>
{{!--
I want to commend out the following code:
{{ ... some Curlybars expressions }}
--}}
上記のテンプレートは、以下のようにレンダリングされます。
<h1>Article</h1>
<p>Some details on the article</p>
リテラル
Curlybarsはリテラルの概念をサポートしており、記述どおりに正確に値を解釈できます。リテラルは、文字列、ブール値、数値の3つのデータ型のいずれかの値をとります。
文字列を表現するには、引用符と二重引用符のどちらを使用してもかまいませんが、両方を混在させることはできません。たとえば、'this is a valid string'
および"this is valid as well"
のように記述できますが、"this is not valid'
と記述することはできません。
数値は正数でも負数でもかまいません。123
は有効な正数であり、+123
も同じ値を表します。00123
も有効な値であり、同様に-123
も有効な値です。
ブール値は、true
とfalse
で表されます。それ以外の記法はありません。たとえば、CurlybarsではTRUE
およびFALSE
はブール値として解釈されません。
リテラルはレンダリングできます。例:
A string: {{ 'hello world' }}
A boolean: {{ true }}
A number: {{ 42 }}
このページは、以下のようにレンダリングされます。
A string: 'hello world'
A boolean: true
A number: 42
プロパティ
ヘルプセンター内のすべてのテンプレートは、ヘルプセンターに関するデータを表す「コンテキスト」にアクセスできます。たとえば、「記事ページ」のテンプレートには、article
というオブジェクトがあります。これは、ユーザーによってリクエストされた記事の構成を表します。テンプレート内で使用できるすべてのプロパティについては、developer.zendesk.comで「Help Center Templates(ヘルプセンターのテンプレート)」を参照してください。
ドット記法を使用して、オブジェクトから特定の情報を引き出します。シンプルな例としては、article.title
のように記述します。
プロパティの完全修飾名は、「パス」と呼ばれることもあります。たとえば、name
はauthor
オブジェクトのプロパティですが、article.author.name
はそのパスです。
プロパティの値は、二重の波かっこで囲んで表すことができます。上の例に戻ると、記事の作成者の名前を別の段落に表示したいとします。
<h1>Article</h1>
<p>Author: {{article.author.name}}</p>
たとえば、ユーザーがJohn Venturiniというエージェントの書いた記事を表示したいとします。テンプレートは、以下のようにレンダリングされます。
<h1>Article</h1>
<p>Author: John Venturini</p>
また、記事そのものをレンダリングすることもできます。article
オブジェクトには、body
プロパティがあり、記事のコンテンツが含まれています。テンプレートを次のように編集して、記事の本文をレンダリングします。
<h1>Article</h1>
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
条件文
テンプレート言語を使用すると、プロパティ値のレンダリングだけでなく、テンプレートにレンダリングの条件式を追加できます。
たとえば、要求された記事が社内向けの場合に、HTMLのスピネットをレンダリングできます。記事ページのコンテンツに含まれるarticle.internal
プロパティは、記事が社内向けのものである場合にtrue
を返し、そうでない場合はfalse
を返します。
この情報を使って、if
ブロックを作成できます。if
式は、trueかfalseになる条件を指定するものです。いずれかの結果によって、ブロック内のコンテンツがレンダリングされるかどうかが決まります。基本的なシンタックスは次のようになります。
{{#if condition}}
This is rendered if the condition is true.
{{/if}}
このテンプレートの例は、次のように変更できます。
<h1>Article</h1>
{{#if article.internal}}
<p>This article is internal.</p>
{{/if}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
条件がfalseの場合に、ブロックがレンダリングされるようにもできます。その場合には、unless
ブロックを使用します。シンタックスはif
ブロックと同じで、次のようになります。
{{#unless condition}}
This is rendered if the condition is false.
{{/unless}}
元の例に戻り、記事が内部向けのものでない場合に、メッセージがレンダリングされるようにしたいとします。テンプレートを以下のように変更します。
<h1>Article</h1>
{{#if article.internal}}
<p>This article is internal.</p>
{{/if}}
{{#unless article.internal}}
<p>This is a publicly visible article!</p>
{{/unless}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
「trueの場合はこれを実行し、それ以外の場合はこちらを実行する」のような条件ロジックは、通常、if-else
ブロックで処理します。シンタックスは以下のようになります。
{{#if condition}}
This is rendered if the condition is true.
{{else}}
This is rendered if the condition is false.
{{/if}}
このプレースホルダの前後のメッセージは、必要に応じて変更できます。
<h1>Article</h1>
{{#if article.internal}}
<p>This article is internal.</p>
{{else}}
<p>This is a publicly visible article!</p>
{{/if}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
unless
ブロックには、unless-else
のバリアントもあります。これを以下のように使って、if-else
ブロックと同じ結果を得ることができます。
<h1>Article</h1>
{{#unless article.internal}}
<p>This is a publicly visible article!</p>
{{else}}
<p>This article is internal.</p>
{{/unless}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
条件式を評価する
条件は、主にarticle.internal
など、trueまたはfalseのブール値をとるヘルプセンタープロパティです。一部のプロパティはブール値をとりません。これらのプロパティは次のように評価されます。
-
値が数値の場合、0はfalseで、それ以外の値はすべてtrue
-
値が文字列の場合、空の文字列はfalseで、それ以外の値はすべてtrue
-
値がオブジェクトの集合の場合、空の集合はfalseで、それ以外の集合はすべてtrue
-
値がnullの場合、式はfalse
数値をチェックする条件式ロジックを設定すると仮定します。記事ページには、記事内のコメントの合計数を含むarticle.comment_count
プロパティがあります。if
条件を使用して、カウントが0
でないことをテストし、ちょっとした愉快なメッセージを表示できます。例:
<h1>Article</h1>
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
{{#if article.comment_count}}
<p>Yahoo! This article has got some comments!</p>
{{/if}}
ホワイトスペースを削除する
Curlybarsがテンプレートを処理する場合、逐語的文字列はそのまま表示されます。この処理は、ほとんどの場合、正常に実行されます。ただし、場合によっては、式に隣接する空白文字に処理を加える必要があります。たとえば、次のコードがあります。
<a href="..." class="{{#if highlighted}} highlight {{/if}}">Click me!</a>
このコードは、highlighted
がtrueの場合に、次のようにレンダリングされます。
<a href="..." class=" highlight ">Click me!</a>
highlightという単語の前後に空白文字が挿入されています。このままでも表示に問題はありませんが、空白文字をレンダリングせずにテンプレート内に挿入したままにしておく方法はないのでしょうか。チルド文字(~)を使用すればできます。
チルド文字を開き波かっこまたは閉じ波かっこに追加することで、かっこで囲んだ文字列からホワイトスペースを削除できます。例:
<a href="..." class="{{#if highlighted~}} highlight {{~/if}}">Click me!</a>
チルダ記号により、highlightという単語の前後の空白文字が次のように削除されます。
<a href="..." class="highlight">Click me!</a>
チルド文字は、空白文字の挿入や改行に影響する空白文字(画面に文字として現れないもの)を削除します。たとえば、新規行、タブ、改行、ラインフィード、シンプルな空白などを削除します。つまり、極端な例をとると、上述の複数行にわたるif
ブロックを、読みやすく表記できます。例:
<a href="..." class="
{{~#if highlighted~}}
highlight
{{~/if~}}
">Click me!</a>
これは、次のようにレンダリングされます
<a href="..." class="highlight">Click me!</a>
このコード例は、実際には役に立ちませんが、チルド文字の使用は場合によって非常に有効です。
ヘルパー
一部のテンプレートで必要な操作は、データにアクセスして表示し、条件ロジックをいくつか追加するだけです。とはいえ、機能を追加したい場合もあります。たとえば、ローカライズした文字列を、ページのリクエスタのロケールごとに変更して表示したい場合や、長すぎる文字列を切り捨てたい場合などです。
このような機能は、テンプレートでヘルパーを使用して追加することができます。テンプレート内で使用できるすべてのヘルパーについては、developer.zendesk.comで「Help Center Templates(ヘルプセンターのテンプレート)」を参照してください。
記事ページテンプレート内で、excerpt
というヘルパーを使用して、文字列を切り捨てることができます。この記事の例は、記事のタイトルを短くして表示する必要がある場合を想定しています。これを行うには、テンプレートを以下のように変更します。
<h1>{{excerpt article.title characters=50}}</h1>
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
上記の例では、波かっこを使用してヘルパーを呼び出しています。excerpt
ヘルパーは、文字列に解決される式で構成されるパラメータを受け取ります。ヘルパーのcharacters
オプションに、維持する文字数を指定します。characters
オプションは必須指定ではありません。指定しない場合、デフォルト値が使用されます。詳細については、ヘルプセンターのテンプレートで、excerptの項を参照してください。
ヘルパーを呼び出すシンタックスは{{<helper> [<param> ...] [<key=value> ...]}}
です。必須要素はヘルパーの名前だけです。パラメータとオプションを指定する必要があるかどうかは、ヘルパーごとに異なります。
次に、テンプレートを更新して、作成者の名前がJohn Venturiniの場合に愉快なメッセージを表示したいとします。あいにく、article.author.name
が"John Venturini"
と等しいかどうかを、if
条件を使用して調べることはできません。if
は1つの式にしか有効にならないからです。==
などの比較演算子は使用できません。
では、どのようにしてロジックを追加するのでしょうか。それには、is
ヘルパーを使用します。等価性を表し、テストするために、2つのパラメータをとります。例:
<h1>{{excerpt article.title characters=50}}</h1>
{{#is article.author.name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{/is}}
<article>{{article.body}}</article>
上の例のスニペットは、作成者がJohn Venturiniであった場合に愉快なメッセージを表示します。では、作成者がJohn Venturiniでなかった場合に別のメッセージを表示する場合の記述はどのようになるでしょうか。実は、is
にはelse
ブロックを含めることができ、if-else
ステートメントと同じように使用できるのです。作成者がJohn Venturiniでなかった場合に元のメッセージを表示するには、else
ブロックを追加します。
<h1>{{excerpt article.title characters=50}}</h1>
{{#is article.author.name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{article.author.name}}</p>
{{/is}}
<article>{{article.body}}</article>
スコープを変更する
ドット記法を使用するデータへのアクセスは、特に、必要な情報へのパスがあまり長くない場合には明快な方法です。例:article.title
。ただし、状況によっては、長いパスを使用してプロパティにアクセスしたい場合があります。例:article.author.name
。必要に応じて、テンプレート内で長いパスを使用することもできます。たとえば、以下の例では、作成者の名前とアバターを追加しています。
<h1>{{excerpt article.title characters=50}}</h1>
<img src="{{article.author.avatar_url}}" alt="Author's avatar" height="42" width="42">
{{#is article.author.name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{article.author.name}}</p>
{{/is}}
<article>{{article.body}}</article>
上記のスニペットは正しく動作しますが、プロパティのパスが長すぎて、コードが読みにくくなっています。この問題を回避するには、with
コンストラクタを使用する方法があります。with
は、関連付けられているコードブロック内で使用するために、基本のコンテキストを表すパラメータを1つとります。シンタックスは以下のようになります。
{{#with <context>}}
...
{{/with}}
先ほどの例を次のように改良できます。
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
<img src="{{avatar_url}}" alt="Author's avatar" height="42" width="42">
{{#is name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{name}}</p>
{{/is}}
{{/with}}
<article>{{article.body}}</article>
article.author
パラメータにより、ブロックのどのパスにもarticle.author
を含める必要がなくなりました。したがって、上記ブロック内の{{name}}
は、ブロック外のarticle.author.name
と同じ意味を表します。
article.author.name
をブロック内で使用することはできません。ブロック内で使用すると、article.author.article.author.name
と評価されるからです。同様に、ブロック内からarticle.title
を使用して記事のタイトルにアクセスすることはできません。記事オブジェクトはルートコンテキスト内でのみアクセス可能で、それはブロック外だからです。
with
が設定されたコンテキストをエスケープして、外部のコンテキストにアクセスするには、パス内で../
記法を使用します。with
ブロック内の記事のタイトルは、次のように記述してレンダリングすることもできます。
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
{{../article.title}}
<img src="{{avatar_url}}" alt="Author's avatar" height="42" width="42">
{{#is name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{name}}</p>
{{/is}}
{{/with}}
<article>{{article.body}}</article>
同じパス内で../
記法を繰り返し使用できます。このように記述することで、コンテキストの数だけ繰り返します。たとえば、次の例も、期待どおりに動作します。
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article}}
{{#with author}}
{{../../article.title}}
...
{{/with}}
<article>{{article.body}}</article>
万全の策として、作成者が指定されていない場合に、特定のメッセージが表示されるようにすることもできます。その場合は、次のようにif
ブロックを使用します。
<h1>{{excerpt article.title characters=50}}</h1>
{{#if article.author}}
{{#with article.author}}
...
{{/with}}
{{else}}
No author is present for this article!
{{/if}}
<article>{{article.body}}</article>
なお、ヘルプセンターでは、article.author
は実際には決してnullになりません。ここでは、コードの記述法を示すために、nullになると仮定しているだけです。
上記のスニペットも正しく動作しますが、with
コンストラクタでelse
ブロックを使用することで、同じ結果を得ることもできます。elseブロックは、パラメータが偽である場合に実行されます。上記の例は、以下のように変更できます。
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
...
{{else}}
No author is present for this article!
{{/with}}
<article>{{article.body}}</article>
else
ブロックを使用することで、コードが読みやすくなります。
ルートコンテキストをヘルパーに渡す
this
キーワードを使用して、現在のルートコンテキストをヘルパーに渡します。作成者に関する情報を表示するためにarticle
オブジェクトをパラメータとして受け取るrender_author
ヘルパーがあるとします。this
キーワードは、次のように使用できます。
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article}}
{{render_author this}}
{{/with}}
<article>{{article.body}}</article>
this
article
として解決されます。
配列内のアイテムにアクセスする
ヘルプセンターの一部のプロパティは、オブジェクトの配列から成ります。たとえば、attachments
プロパティは、添付ファイルの配列で構成されます。
配列内のアイテムにアクセスするには、アイテムごとに反復処理を行う必要があります。each
ヘルパーがこの処理を行います。例:
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
...
{{/with}}
<article>{{article.body}}</article>
{{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{/each}}
上記のスニペットは、すべての添付ファイルを列挙します。各リストアイテムは、それぞれ添付ファイルの固有データを表示します。たとえば、url
、name
、size
などです。
with
と同様、each
が変更するのはブロック内のコンテキストです。つまり、ブロック外のコンテキストにアクセスしたい場合は、../
記法を使用できます。
配列が空の場合に、メッセージがレンダリングされるようにもできます。これは、if
ブロックを次のように記述することで、簡単に実現できます。
...
{{#if attachments}}
{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{/each}}
{{else}}
Sorry, no attachments available!
{{/if}}
このままでも正しく動作しますが、else
ブロックを使用すると、コードがより読みやすくなります。
...
{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{else}}
Sorry, no attachments available!
{{/each}}
length
すべての配列には、配列内の要素の数を示す暗黙的なlength
プロパティがあります。たとえば、添付ファイルの数を表示したい場合、length
プロパティを次のように指定します。
...
There are {{attachments.length}}.
{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{/each}}