Templating / Fetching content
Note: You are currently reading the documentation for Bolt 4.0. Looking for the documentation for Bolt 5.2 instead?
Besides content that is already available on a specific ContentType listing-
page or single-page (Record and Records), you can
directly fetch content from the database. For this you can use the
{% setcontent ... %}
tag. The following example will get the content record
with slug 'about' from the 'pages' ContentType:
{% setcontent about = 'page/about' %}
{{ dump(about) }}
There are a lot of options for the setcontent
tag. Most are optional, and all
can be used together any way you'd like. The most basic syntax is:
{% setcontent _variable_ = '_contenttype_' %}
This will set a variable to contain the records of the given contenttype.
For example: {% setcontent mypages = 'pages' %}
will set {{ mypages }}
to
an array of all the records in 'pages'.
Trimming the amount of results¶
Normally, you don't need all records, but a subset of the available records.
You can limit the number of records by using a where
clause (more on that
below), but often it's easier to use the shortcut that Bolt provides.
If you need a single record, and know its id
or slug
, you can do this:
{# get the page with slug 'about' #}
{% setcontent about = 'page/about' %}
{# get the newsitem with id 12 #}
{% setcontent news = 'news/12' %}
If you need the '5 latest pages' or '3 first reviews', there's also a shortcut for that:
{% setcontent latestpages = 'pages' latest limit 5 %}
{{ dump(latestpages) }}
and:
{% setcontent firstreviews = 'reviews' earliest limit 3 %}
{{ dump(firstreviews) }}
Using where
¶
If you need more specific criteria to select the records on, you can use the
where
clause. The parameters must be listed in a hash.
{# get all pages with author id '2' #}
{% setcontent pages = 'pages' where { author: 2 } %}
{# get all events with eventdate '2012-10-15' #}
{% setcontent myevents = 'events' where { eventdate: '2012-10-15' } %}
The above examples selected records based on the parameter being equal to the matching field in the available records. It's also possible to use modifiers for the values, to select based on 'smaller than' or 'does not equal':
{# get all pages not created by user '1' #}
{% setcontent mypages = 'pages' where { author: '!1' } %}
{# get all products where price is not empty #}
{% setcontent myproducts = 'products' where { price: '!' } %}
{# get all events with eventdate before '2012-10-15' #}
{% setcontent myevents = 'events' where { eventdate: '<2012-10-15' } %}
{# get all blog entries which have been published before last monday #}
{% setcontent myarticles = 'entries' where { status: 'published', publishedAt: '< last monday' } %}
{# get all books with amountsold over 1,000 #}
{% setcontent mybooks = 'books' where { amountsold: '>1000' } %}
{# get all blog entries except current record, negating a variable in the 'where' clause #}
{% set pageid = record.id %}
{% set whereid = '!' ~ pageid %}
{% setcontent blog_entries = 'blog' where { id: whereid } %}
You can also pass an object-like variable to the where
clause, if this is more convenient for you.
This is useful when you're building the query dynamically, e.g. based on user input.
{% set condition = {'title': '%lorem%', 'status': "published"} %}
{% setcontent records = 'pages,showcases' where condition %}
Tip: When using '<=2012-12-01'
Bolt only selects dates before or equal to '2012-12-01 00:00:00'
.
If you want to include December 1st, use '<2012-12-02'
.
The %like%
option¶
{# get all pages with titles that contain 'ipsum' #}
{% setcontent mypages = 'pages' where { title: '%ipsum%' } %}
The %like%
option is case-insensitive, and does not take word boundaries into
account. So, this example will return the pages with these titles:
- 'Lorum ipsum dolor'
- 'LORUM IPSUM DOLOR'
- 'Lorumipsumdolor'
- 'ipsumdolor'
But not:
- 'Lorum ipsüm dolor'
- 'Lorum ips um dolor'
Tip: When using only one %
, Bolt
will match only the beginning or the end of the field. For example:
'lore%'
and '%olor'
will both match "Lorem Ipsum
Dolor", but 'ipsu%'
won't.
Using taxonomies¶
You can use the same syntax to get records with a specific taxonomy. Note that you should always use the plural name of the taxonomy in the query:
{# get all events in the category 'music' #}
{% setcontent myevents = 'events' where { categories: 'music' } %}
{# get all pages with tag 'book' or 'movie' #}
{% setcontent mypages = 'pages' where { tags: 'book || movie' } %}
Selecting on dates¶
You can use several 'shortcuts' for selecting records with dates in the past or future. Some examples are:
now
- The current date and time.today
- The current date, today at midnight.tomorrow
- The date of tomorrow, at midnight.yesterday
- The date of yesterday, at midnight.last year
next thursday
You can use these date notations like this:
{# Selecting pages published _before_ yesterday #}
{% setcontent mypages = 'pages' where { publishedAt: '<yesterday' } %}
{# If you want to include yesterday in your `where`, use 'before today' #}
{% setcontent mypages = 'pages' where { publishedAt: '<today' } %}
{# Selecting pages published earlier today, or in the future #}
{% setcontent mypages = 'pages' where { publishedAt: '>today' } %}
{# Selecting pages published today only #}
{% setcontent mypages = 'pages' where { publishedAt: '>today && <tomorrow' } %}
Tip: When using 'where' statements with a field
that is a date, you can use relative, textual dates, like 'last monday'
or '> this year'
. Internally, Bolt uses the PHP
strtotime()
function for this, so we refer to its
manual page for details.
Like mentioned above, you can add more than one parameter to the where clause:
{# get all pages not created by 'pete', and created after july 2012, with a .jpg image #}
{% setcontent mypages = 'pages' where { author: '!3', createdAt: '>2012-07-31', image: '%.jpg%' } %}
'AND' and 'OR'¶
You can use the &&
and ||
-parameters to select on two criteria for any
field. However, you can't use something like where { ownerid: '!3', ownerid: '!4'}
because of the way hashes work in twig: The second ownerid
would
overwrite the first. Instead, you can use the &&
and ||
-parameters to
either select using AND
or OR
. examples:
{# get all pages created by ownerid '3' or '4' #}
{% setcontent mypages = 'pages' where { author: '3 || 4' } %}
{# get all pages with an id greater than 29, but smaller or equal to 37 #}
{% setcontent mypages = 'pages' where { id: '>29 && <=37' } %}
Please note that using these operators, it'll be quite easy to create a where statement that will never give good results:
{# This will _always_ match: #}
{% setcontent mypages = 'pages' where { author: '!3 || !4' } %}
{# This will never work: #}
{% setcontent mypages = 'pages' where { id: '<29 && >37' } %}
Getting content for a specific user¶
As you might've noticed, in the examples above, we've used author
a couple
of times to get content specific to a given user. In Bolt, content is stored
with a reference to the author. This means that you
cannot do things like this:
{# get all pages created by user 'bob' #}
{% setcontent mypages = 'pages' where { author: 'bob' } %}
Instead, you'll need to use author: 1
. If you don't know the id
, but
you do know their name, you can use the getuser()
function.
{# get all pages created by user 'bob' #}
{% set myuserid = getuser('bob').id %}
{% setcontent mypages = 'pages' where { author: myuserid } %}
{# or, on one line #}
{% setcontent mypages = 'pages' where { author: getuser('bob').id } %}
Using limit
¶
There's a default built-in limit to the amount of records returned, which is 20. It is good
practice to limit the maximum number of records, by adding a limit
clause.
{# get 10 pages created by 'bob' #}
{% setcontent mypages = 'pages' where { author: getuser('bob').id } limit 10 %}
Paginating results¶
By default, Bolt will paginate records with the default for the limit
directive. It will
also match the current page, using the ?page=2
query parameter in the URL, e.g.
example.org/entries?page=2
Additionally, you can specify/override the current page of results using the page
directive:
{% setcontent entries = 'entries' page 4 %}
To read more about pagination in Bolt, check the Paging content page.
Ordering results¶
The results can be sorted by any of the fields of the ContentType, using the
orderby
clause. You can sort either ascending or descending. The order is
determined by the inclusion (or omission) of the minus before the name of
the field: title
vs. -title
.
{# get 10 pages, sorted alphabetically on title #}
{% setcontent mypages = 'pages' limit 10 orderby 'title' %}
{# get the 10 latest modified pages, sorted modifiedAt descending #}
{% setcontent mypages = 'pages' limit 10 orderby '-modifiedAt' %}
{# If two records have the same modifiedAt, you can order them by publishedAt descending #}
{% setcontent mypages = 'pages' limit 10 orderby '-modifiedAt,-publishedAt' %}
{# You can chain as many orderby's like this as you need #}
{% setcontent mypages = 'pages' limit 10 orderby '-modifiedAt,-publishedAt,-createdAt,title,subtitle' %}
Note that the records are fetched from the database, according to the orderby
parameter. If you use orderby 'title'
, you will get records with titles
starting with 'a'.
Random order¶
To get 'random' selection of records, you can use the random
directive,
either in combination with the limit
directive or on its own.
The example below will return a pseudo-randomised selection of 3 testimonials:
{% setcontent testimonials = 'testimonials' random limit 3 %}
One record or multiple records?¶
Sometimes Bolt will return one record, and sometimes a set of records. What makes the difference?
{% setcontent mypage = 'page/about' %}
{{ mypage }} {# mypage is one record #}
{% setcontent mypages = 'page' latest 5 %}
{% for mypage in mypages %}
{{ mypage }} {# mypages is an array that we can iterate over #}
{% endfor %}
Bolt tries to make an assumption about how you want to use it, based on what you're requesting. By default, an array is returned, unless one of the following is the case:
{% setcontent foo = 'bar/1' %}
or{% setcontent foo = 'bar/qux' %}
: When requesting one specific record, only one is returned.{% setcontent foo = 'pages' .. returnsingle %}
: If thereturnsingle
parameter is passed, Bolt assumes you only need one result.
If you use limit 1
, you will get an array with 1 record. Unless, of course,
one of the above criteria was met.
To override the default behaviour, you can explicitly request either a single record or multiple records:
{% setcontent mypage = 'pages' returnsingle %}
{# by specifying `returnsingle`, Bolt will return a single page from the pages ContentType #}
{% setcontent arrayofpages = 'pages' returnmultiple %}
{# by specifying `returnmultiple`, Bolt will return an array of pages, even if it is an array of 1 #}
Using the printquery
option¶
If you're working on selecting some content, but aren't quite getting the
desired results, you can add printquery
to the {% setcontent %}
- tag. Doing
this will output the SQL query Bolt creates and executes. For example:
{% setcontent entries = 'entries' latest 5 printquery %}
will show:
SELECT content FROM Bolt\Entity\Content content WHERE content.contentType = :ct0 AND content.status = :status_1 ORDER BY content.publishedAt DESC
ct0: entries
status_1: published
Couldn't find what you were looking for? We are happy to help you in the forum, on Slack or on Github.