GHOST CMS - Functional Helpers功能助手

Functional Helpers

Functional helpers are used to work with data objects. Use this reference list to discover what each handlebars helper can do when building a custom Ghost theme.

Available functional helpers

 


 

is

Usage: {{#is "contexts"}}

Description

The {{#is}} helper allows you to check the context of the current route, i.e. is this the home page, or a post, or a tag listing page. This is useful when using shared partials or layouts, to output slightly different context in different places on your theme.

Usage

The is helper takes a single parameter of a comma-separated list containing the contexts to check for. Similar to the has helper, the comma behaves as an orstatement, with and being achieved by nesting helpers.

{{#is "post, page"}}
   ... content to render if the current route represents a post or a page ...
{{/is}}

As with all block helpers, it is possible to use an else statement:

{{#is "home"}}
  ... output something special for the home page ...
{{else}}
  ... output something different on all other pages ...
{{/is}}

If you only want the reverse, or negation, you can use the ^ character:

{{^is "paged"}}
 ...if this is *not* a 2nd, 3rd etc page of a list...
{{/is}}

Contexts

The following contexts are supported:

  • home - true only on the home page
  • index - true for the main post listing, including the home page
  • post - true for any individual post page, where the post is not a static page
  • page - true for any static page
  • tag - true for any page of the tag list
  • author - true for any page of the author list
  • paged - true if this is page 2, page 3 of a list, but not on the first page
  • private - true if this is the private page shown for password protected sites

foreach

Usage: {{#foreach data}}{{/foreach}}

Description

{{#foreach}} is a special loop helper designed for working with lists of posts. It can also iterate over lists of tags or users if needed. The foreach helper will output the content placed between its opening and closing tags {{#foreach}}{{/foreach}} once for each item in the collection passed to it.

The {{#foreach}} helper is context-aware and should always be used instead of Handlebars each when working with Ghost themes.

Simple Example

The main use of the {{#foreach}} helper in Ghost is iterating over the posts to display a list of posts on your home page, etc:

{{#foreach posts}}
<article class="{{post_class}}">
  <h2 class="post-title"><a href="{{url}}">{{title}}</a></h2>
  <p>{{excerpt words="26"}} <a class="read-more" href="{{url}}">&raquo;</a></p>
  <p class="post-footer">
    Posted by {{primary_author}} {{tags prefix=" on "}} at <time class="post-date" datetime="{{date format='YYYY-MM-DD'}}">{{date format="DD MMMM YYYY"}}</time>
  </p>
</article>
{{/foreach}}

Data Variables

When inside a {{#foreach}} block, you have access to a set of data variables about the current iteration. These are:

  • @index (number) - the 0-based index of the current iteration
  • @number (number) - the 1-based index of the current iteration
  • @key (string) - if iterating over an object, rather than an array, this contains the object key
  • @first (boolean) - true if this is the first iteration of the collection
  • @last (boolean) - true if this is the last iteration of the collection
  • @odd (boolean) - true if the @index is odd
  • @even (boolean) - true if the @index is even
  • @rowStart (boolean) - true if columns is passed and this iteration signals a row start
  • @rowEnd (boolean) - true if columns is passed and this iteration signals a row end

Usage

{{#foreach}} is a block helper. The most common use case in Ghost, is looping through posts.

{{#foreach posts}}
<h2><a href="{{url}}">{{title}}</a></h2>
<p>{{excerpt}}</p>
{{/foreach}}

{{else}} and negation

Like all block helpers, {{#foreach}} supports adding an {{else}} block, which will be executed if there was no data to iterate over:

{{#foreach tags}}
<a href="{{url}}">{{name}}</a>
{{else}}
<p>There were no tags...</p>
{{/foreach}}

The limit attribute

Passing {{#foreach}} a limit attribute, will tell it stop after a certain number of iterations.

{{#foreach posts limit="3"}}
<a href="{{url}}">{{name}}</a>
{{/foreach}}

Note that as the {{#foreach}} helper is only passively iterating over data, not actively fetching it, if you set limit to a number higher than the number of items in the collection, it will have no effect.

The from and to attributes

Passing {{#foreach}} a from or to attribute will change the items which are output. Both attributes are 1-indexed and inclusive, so from="2" means from and including the 2nd post.

{{#foreach posts from="2" to="5"}}
<a href="{{url}}">{{name}}</a>
{{/foreach}}

Data variable examples

@index, @number and @key

{{@index}} is the 0-based index of the collection - that is the "count" of the loop. It starts at 0 and then each time around the loop, {{@index}} increases by 1. This is useful for adding numbered classes:

{{#foreach posts}}
  <div class="post-{{@index}}">{{title}}</div>
{{/foreach}}

{{@number}} is very similar to @index, but starts at 1 instead of 0, which is useful for outputting numbers you want users to see, e.g. in styled numbered lists:

<ol>
{{#foreach posts}}
  <li>
    <a href="{{url}}">
      <span class="number" aria-hidden="true">{{@number}}</span>{{title}}
    </a>
  </li>
{{/foreach}}
</ol>

{{@key}} will contain the object key, in the case where you iterate over an object, rather than an array. There's no real use case for this in Ghost at present.

@first & @last

The following example checks through an array or object e.g posts and tests for the first entry.

{{#foreach posts}}
  {{#if @first}}
    <div>First post</div>
  {{/if}}
{{/foreach}}

We can also nest if statements to check multiple properties. In this example we are able to output the first and last post separately to other posts.

{{#foreach posts}}
    {{#if @first}}
    <div>First post</div>
    {{else}}
        {{#if @last}}
            <div>Last post</div>
        {{else}}
            <div>All other posts</div>
        {{/if}}
    {{/if}}
{{/foreach}}

@even & @odd

The following example adds a class of even or odd, which could be used for zebra striping content:

{{#foreach posts}}
    <div class="{{#if @even}}even{{else}}odd{{/if}}">{{title}}</div>
{{/foreach}}

Block Params

Block params allow you to name the individual item being operated on inside the loop, E.g.

{{#foreach posts as |my_post|}}
   {{#my_post}}
      <h1>{{title}}</h1>
    {{/my_post}}
{{/foreach}}

Which is much the same as doing posts.forEach(function (my_post) {} in JavaScript. Useful with advanced features like the {{get}} helper.

 


 

has

Usage: {{#has tag="value1,value2" author="value"}} {{#has slug=../slug}} {{#has number="nth:3"}} {{#has any="twitter, facebook"}} {{#has all="twitter, facebook"}}

Description

{{#has}} is like {{#if}} but with the ability to do more than test a boolean. It allows theme developers to ask questions about the current context and provide more flexibility for creating different layouts.

Like all block helpers, {{#has}} supports adding an {{else}} block or using ^ instead of # for negation - this means that the {{#has}} and {{else}} blocks are reversed if you use {{^has}} and {{else}} instead. In addition, it is possible to do {{else has ...}}, to chain together multiple options like a switch statement.

Simple Example

The {{#has}} helper can be combined with internal tags, to display different information for different types of posts. E.g. you can implement a link-style post by adding an internal tag of #link and using the has helper to detect it:

{{#post}}
  {{#has tag="#link"}}
     {{> "link-card"}}
  {{else}}
    {{> "post-card"}}
  {{/has}}
{{/post}}

Usage

The {{#has}} helper supports four different types of "questions":

  • Post has tag or author
  • Context has slug or id
  • Context has any or all properties set
  • Foreach loop number or index

Questions are asked by providing attribute-value pairs, e.g. tag="tag-name". You can pass multiple attributes, and the {{#has}} helper will always treat this as an OR.

E.g. You can look for a post with a slug of "welcome" OR a tag of "getting started":

{{#has slug="welcome" tag="getting-started"}}
  ...Will execute if the slug is welcome OR the tag is getting-started...
{{/has}}

Post tag or author

Comma Separated List

{{#has tag="photo"}}{{/has}}
{{#has tag="photo, video"}}{{/has}}
{{#has author="Joanna Bloggs"}}{{/has}}

Specifically when inside the context of a post, you can use the {{#has}} helper to find out if the post has a particular tag or author. Both the tag and author attributes take a comma separated list. If you pass multiple values separated by a comma, these will be treated as an OR.

{{#has tag="General, News"}}
  ...Will execute if the post has a tag of General or News...
 {{/has}}

Tag and author matching is a lowercase match on the tag name or author name, which ignores special characters. This behaviour will be upgraded in future to try to match on either slug or name.

Counting

The author and tag attribute accepts a counting value. You can choose between:

  • count:[number]
  • count:>[number]
  • count:<[number]

This functionality can be helpful when designing a theme. You can change the behaviour if a post has only one author or more than 1.

{{#has tag="count:1"}}{{/has}}
{{#has tag="count:>1"}}{{/has}}
{{#has author="count:<2"}}{{/has}}

Slug or id

{{#has slug="welcome"}}{{/has}}
{{#has slug=../../slug}}{{/has}}
{{#has id=post.id}}{{/has}}

If you're in the context of an object that has a slug (e.g. post, author, tag and navigation items) you can use the {{#has}} helper to do an exact match. Similarly for all objects that have an ID.

You can either pass the {{#has}} helper a string wrapped in quotes, or a path to a data value from else where in the template data. For example, the following code does an exact match on the string "welcome". If the post's slug is the same, the code inside the has helper will execute.

{{#has slug="welcome"}}
  ... do something..
{{/has}}

Alternatively, you can pass a handlebars path, which references a different piece of data to match against:

{{#has slug=../post.slug}}
  ...do something...
{{/has}}

Any or all

The any comparison will return true if any one of the properties is set in the current context, with support for paths and globals:

{{#has any="twitter, facebook, website"}}
{{#has any="author.facebook, author.twitter,author.website"}}
{{#has any="@blog.facebook, @blog.twitter, @labs.subscribers"}}

Similarly, the all comparison will return true only when all of the properties are set:

{{#has all="@labs.subscribers,@labs.publicAPI"}}

Foreach loop number or index

{{#has number="3"}}{{/has}} // A single number
{{#has number="3, 6, 9"}}{{/has}} // list of numbers
{{#has number="nth:3"}}{{/has}} // special syntax for nth item
{{!-- All of these work exactly the same for index --}}

When you're inside a {{#foreach}} loop of any kind, you have access to two special data variables called @index and @number@index contains the 0-based index or count of the loop, and @number contains a 1-based index. That is each time around the loop these values increase by 1, but @index starts at 0, and @number starts at 1.

The {{#has}} helper will let you check which number/index of the iteration you are on using the 3 different styles of matching shown above. For example, if you have a list of posts and want to inject a special widget partial every 3rd post, you could do so using the nth:3 pattern:

{{#foreach posts}}
  {{#has number="nth:3"}}
     {{> "widget"}}
  {{/has}}

  {{> "post-card"}}
{{/foreach}}

Example Code

To determine if a post has a particular tag:

{{#post}}
    {{#has tag="photo"}}
        ...do something if this post has a tag of photo...
    {{else}}
        ...do something if this posts doesn't have a tag of photo...
    {{/has}}
{{/post}}

You can also supply a comma-separated list of tags, which is the equivalent of an OR query, asking if a post has any one of the given keywords:

{{#has tag="photo, video, audio"}}
    ...do something if this post has a tag of photo or video or audio...
{{else}}
    ...do something with other posts...
{{/has}}

You can do an AND query by nesting your {{#has}} helpers:

{{#has tag="photo"}}
    ...do something if this post has a tag of photo..
    {{#has tag="panorama"}}
       ...if the post has both the photo and panorama tags
    {{/has}}
{{else}}
    ...do something with other posts...
{{/has}}





if

Usage: {{#if featured}}{{/if}}

The {{#if}} block helper comes built in with Handlebars.

Description

{{#if}} allows for testing very simple conditionals, and executing different template blocks depending on the outcome.

The conditionals that can be tested are very simple, essentially only checking for 'truthiness'. The evaluation rules are explained in the section below.

Like all block helpers, {{#if}} supports adding an {{else}} block or using ^ instead of # for negation - this means that the {{#if}} and {{else}} blocks are reversed if you use {{^if}} and {{else}} instead. In addition, it is possible to do {{else if ...}}, to chain together multiple options like a switch statement.

Evaluation rules

The if helper takes a single value, and evaluates whether it is true or false. Any passed in value which is equivalent to false0undefinednull"" (an empty string) or [](an empty array) is considered false, and any other value is considered true.

  • Any boolean value, like the featured flag on a post, will evaluate to true or false as you expect.
  • Any string value will be true, as long as it is not null or empty
  • All numerical values, with the exception of 0 evaluate to true, 0 is the same as false
  • Any property which doesn't exist or is not set will always evaluate false
  • Empty arrays or objects will be false

Example code

When in the scope of a post, featured is a boolean flag. The following code example will evaluate to true only if the post is marked as featured.

{{#post}}
  {{#if featured}}
   ...do something if the post is featured...
  {{/if}}
{{/post}}

You can also use this to test if any property is set. Strings, like image URLs will evaluate to true as long as one is present, and will be null (false) otherwise:

{{#post}}
  {{#if feature_image}}
     <img src="{{img_url feature_image}}" />
  {{else}}
		 <img src="{{asset "img/default-img.jpg"}}" />
  {{/if}}
{{else}}
<p>No posts to display!</p>
{{/post}}





unless

Usage: {{#unless featured}}{{/unless}}

The {{#unless}} block helper comes built in with Handlebars.

Description

{{#unless}} is essentially the opposite of {{#if}}. If you want to test a negative conditional only, i.e. if you only need the {{else}} part of an {{#if}} statement, then {{#unless}} is what you need.

It works exactly the same as {{#if}} and supports both {{else}} and ^ negation if you want to get really confusing!

Unless also uses the exact same conditional evaluation rules as {{#if}}.

Example code

Basic unless example, will execute the template between its start and end tags only if featured evaluates to false.

{{#unless featured}}
  ...do something...
{{/unless}}

If you want, you can also include an else block, although in the majority of cases, if you need an else, then using {{#if}} is more readable:

// This is identical to if, but with the blocks reversed
{{#unless featured}}
  ...do thing 1...
{{else}}
  ...do thing 2...
{{/unless}}



get

Usage: {{#get "posts"}}{{/get}}

## Description

{{#get}} is a special block helper that makes a custom query to the Ghost API to fetch publicly available data. These requests are made server-side, before your templates are rendered. This means you can fetch additional data, separate from what is provided by default in each context.

In its most basic form it can perform a 'browse' query to create a block of data that represents a list of your posts, authors (users) or tags. That block of data can then be iterated over using the {{#foreach}} helper.

It can also be used to perform a 'read' query that fetches one specific author, post or tag if the relevant resource field - E.g. id or slug is provided as an attribute.

Please note: This is a powerful tool, that has the potential to be overused and cause problems on a site.

Simple Examples

A basic request for posts, this will fetch 15 posts from the API including their related tags and authors.

{{#get "posts" include="tags,authors"}}
    {{#foreach posts}}
        {{title}}
    {{/foreach}}
{{/get}}

A basic request for a single post with id of 2, including its related tags and author data, using a block parameter.

{{#get "posts" id="2" include="tags,authors" as |post|}}
    {{#post}}
        {{title}}
    {{/post}}
{{/get}}

Fetch all tags, and output them using the tags helper:

{{#get "tags" limit="all"}}{{tags}}{{/get}}

Usage

The {{#get}} helper has many more options than most helpers, the following section walks through the various options and how they can be used.

Parameters

The first parameter passed in is the name of the resource that you want to query. This can be either "posts""tags" or "authors".

posts - only published posts can be retrieved

tags - any tag that has a post associated with it

authors - any author who has a post associated with it

Example:

{{#get "posts"}}
    {{! Loop through our posts collection }}
    {{#foreach posts}}
        {{title}}
    {{/foreach}}
{{/get}}

Block Parameters

As with the {{#foreach}} helper, it is possible to use block parameters to rename your returned data collection to make it easier to reference or more distinguishable.

Note: Block Params are entered between pipe symbols, which are vertical bars: |

Usage: as |featuredposts pagination|

The {{#get}} helper supports two parameters entered here. The first entry in the piperefers to your returned data collection. The second entry refers to your pagination object.

Example using block parameters:

{{#get "posts" as |articles pages|}}
    {{! Loop through our articles collection }}
    {{#foreach articles}}
        {{title}}
    {{/foreach}}
    {{! Use our pages (pagination) object }}
    {{pages.total}}
{{/get}}

In the example above we are fetching posts which we will then refer to as articles in our loop and a pagination object called pages.

Using {{else}}

All block helpers support the {{else}} helper, which allows you to output content when the first block doesn't match. In the case of the {{get}} helper, this only happens if there is an error and is mostly useful for debugging whilst developing.

If you want to output different content when there are no results, you will need to use {{else}} with the {{#foreach}} helper.

{{#get "posts" filter="featured:true"}}
    {{! Loop through our featured posts }}
    {{#foreach posts}}
        {{title}}
    {{else}}
    {{! If there are no featured posts}}
       <p>No posts!</p>
    {{/foreach}}
{{else}}
  <p class="error">{{error}}</p>
{{/get}}

Attributes

The attributes that can be passed to the {{#get}} helper exactly match up to the query parameters that you can use in the Ghost JSON API. These allow you to specify the data to look for and how much data is returned. If you're making a 'browse' request (fetching multiple items) you can use any of these attributes and if you're making a 'read' request (fetching a single item by id or slug) only include is available.

limit

Specify the size of your collection

Allowed values: positive integer and 'all'

Default value: 15

It is possible to use the global posts_per_page setting which is 5 by default or it can be configured via the active theme's package.json file. This global value is available via the @config global as @config.posts_per_page.

Examples:

{{! Fetch the 20 most recently published posts }}
{{#get "posts" limit="20"}}{{/get}}

{{! Fetch all published posts }}
{{#get "posts" limit="all"}}{{/get}}

{{! Use the posts_per_page setting}}
{{#get "posts" limit=@config.posts_per_page}}{{/get}}

page

The resulting collection from the {{#get}} query may be paginated, therefore you can choose which page of that collection you want to fetch.

Example:

{{! Fetch the 4th page of results }}

{{#get "posts" limit="5" page="4"}}{{/get}}
{{! In this case where limit = 5, we are accessing posts 16 - 20 }}

order

Specify how your data is ordered before being returned. You can choose any valid resource field in ascending (asc) or descending (desc) order.

Examples:

{{! Fetch the oldest 5 posts }}
{{#get "posts" limit="5" order="published_at asc"}}{{/get}}

{{! Fetch the 5 most recently published posts }}
{{#get "posts" limit="5" order="published_at desc"}}{{/get}}

{{! Fetch posts in alphabetical order of title ([0-9], A->Z) }}
{{#get "posts" limit="5" order="title asc"}}{{/get}}

include

When making an API request, the resulting response will only contain base data from the Resource itself.

A Resource may have additional related data that can be included to expand your collection.

Base Resource data:

  • Post
  • Tag
  • Author

There can be multiple includes separated by a comma.

The Post resource by default has a tags and authors array. These can be expanded to include more information.

Include options for Post: "authors" - expands authors, "tags" - expands tags.

The Author and Tag resources can be expanded to include the post count for each resource.

Include options for Author and Tag: "count.posts"

Note: If you include count.posts you can use it to order your collection.

Examples:

{{! Fetch posts with author }}
{{#get "posts" limit="5" include="authors"}}
    {{#foreach posts}}
        <span>Written by: {{authors}}</span>
    {{/foreach}}
{{/get}}

{{! Fetch posts with author and tags }}
{{#get "posts" limit="5" include="authors,tags"}}
    {{#foreach posts}}
        <p>Written by: {{authors separator=", "}}</p>
        <p>keywords: {{tags separator=", "}}</p>
    {{/foreach}}
{{/get}}

filter

This is a powerful tool that allows you to make a complex logic-based queries on the data to fetch. In its most basic form, you can choose to fetch posts that meet a simple boolean logic such as featured posts:

{{#get "posts" limit="all" filter="featured:true"}}
    {{#foreach posts}}
        <a href="{{slug}}">{{title}}</a>
    {{/foreach}}
{{/get}}

Filtering can be used to specify multiple rules using and or or and can check for booleans, match against strings, look for items within a group, and many other things. For a full breakdown of the filtering syntax and how to use it, please see the Filter documentation in the API docs.

Passing data to filter

When used with the {{#get}} helper, filters can be passed data which is already available within your theme template. For example, if in your post.hbs file you wanted to get 3 more posts by the author of the current post, you can do so as shown here:

{{#post}}
    <h3><a href="{{url}}">{{title}}</a></h3>
    <section class="author-meta">
        <p>Post by: {{primary_author}}</p>
    </section>

    {{#get "posts" filter="authors:{{primary_author.slug}}+id:-{{id}}" limit="3"}}
        <p>More posts by this author:
            <ol>
                {{#foreach posts}}
                <li><a href="{{url}}">{{title}}</a></li>
                {{/foreach}}
            </ol>
        </p>
    {{/get}}
{{/post}}

In this example, we look for posts with the primary_author (which is an alias of authors[0]), that matches the current author and that does not have the same id as the current post, so that we will get 3 different posts.

In some cases, you'll need to wrap the data you pass in with quotes, for example if you pass a title rather than a slug, because it contains spaces, and also if you want to use dates.

{{#post}}
    {{#get "posts" filter="published_at:<='{{published_at}}'+id:-{{id}}" limit="3"}}
    ...
    {{/get}}
{{/post}}

Also be aware that, if you want to filter based on dates, you need to use the data attributes e.g.{{published_at}}, not the {{date}} helper, as helper functions do not get called inside of a filter.

Filtering by primary tag

The primary_tag is a virtual post property and we support filtering by this property.

{{#post}}
    {{#get "posts" filter="primary_tag:{{primary_tag.slug}}" limit="3"}}
        {{#foreach posts}}
            <li><a href="{{url}}">{{title}}</a></li>
        {{/foreach}}
    {{/get}}
{{/post}}

In this example we fetch 3 posts which have the same primary tag as the current post.

Filtering by primary author

The primary_author is a virtual post property and we support filtering by this property.

{{#post}}
    {{#get "posts" filter="primary_author:{{primary_author.slug}}" limit="3"}}
        {{#foreach posts}}
            <li><a href="{{url}}">{{title}}</a></li>
        {{/foreach}}
    {{/get}}
{{/post}}

Limitations

There are a few known limitations with the {{#get}} helper at the moment:

  • {{#get}} helpers may not work correctly when nested.
  • Other async helpers may not work when nested inside a get block (you may see an aSyNcId_### error on your page).
  • You cannot yet filter on count.posts
  • Ordering alphabetically may be case sensitive depending on database.
  • {{pagination}} won't output anything sensible when used inside {{#get}} block, because the get helper can only fetch existing data. It doesn't create a /page/2/ version of the data you are fetching.

 

 

link

Usage: {{#link href="/about/"}}About{{/link}}

Description

{{#link}} is a block helper that creates links with dynamic classes. In its basic form it will create an anchor element that wraps around any kind of string, HTML or handlebars constructed HTML.

With additional options it can have an active class or target behaviour, or onclickJavaScript events. A href attribute must be included or an error will be thrown.

Simple example

{{#link href="/about/"}}..linked content here..{{/link}}

Will output:

<a href="/about/">..linked content here..</a>

All attributes associated with the <a></a> element can be used in {{#link}}. Check out the MDN documentation on the anchor element for more information.

Variables

Handlebars variables can be used for attribute values as well as strings. Variables do not need be wrapped with quotations:

Simple variables example

{{#link href=@site.url}}Home{{/link}}

Advanced variables example

{{#foreach posts}}
  {{#link href=(url) class="post-link" activeClass="active"}}
    {{title}}
  {{/link}}
{{/foreach}}

Dynamic attributes

activeClass

By default the active class outputted by {{#link}} will be nav-current, this is consistent with our navigation helper. However it can be overwritten with the activeClass attribute:

activeClass Example

{{#link href="/about/" activeClass="current"}}About{{/link}}

When on the "/about/" URL it will output:

<a href="/about/" class="current">About</a>

activeClass can also be given false value (activeClass=false), which will output an empty string. Effectively turning off the behaviour.

 

 

posted @ 2019-12-22 22:32  QDuck  阅读(287)  评论(0编辑  收藏  举报