Working with Bolt / ContentTypes and Records
Note: You are currently reading the documentation for Bolt 2.2. Looking for the documentation for Bolt 5.2 instead?
All content in Bolt is stored in the database in a logical and flexible fashion. In general, when you're building a website, you have an idea what kind of content you're going to be managing with the website. Most websites have some sort of 'pages' for generic stuff like 'about us' or 'Company History'.
Most websites will also have some form of news-like items, that are shown based on the date that they were published. Some other sites might have 'book reviews' or 'event dates' or even completely different content. All of these different types of content are called ContentTypes in Bolt, and you can add as many different ContentTypes as you need.
Each ContentType is defined by a couple of fixed, required Fields that are
used internally, but otherwise you're free to define how the content in a
ContentType is structured. For instance, in an 'event', you'll need a date on
which the event takes place. For a 'book review', you'll need an author and
publisher of the book. Other commonly used fields are title
, introduction
or maybe an image
. Some of the Fields are fixed, which means that every
ContentType has them. For example, every ContentType has a Field for id
,
slug
, datecreated
and ownerid
. Below we'll describe how to define
ContentTypes and Fields.
All content on your website is part of one specific ContentType, which automatically defines which fields that piece of content has, which in turn specifies how that piece of content is structured. Each one of those pieces of content is called a Record, and is stored in the database. For example, a single 'event' is a Record of ContentType 'events' and a single 'page' is a Record of ContentType 'pages'.
When you're creating a page on a website that shows listings of several Records, you're using an Array of Records. For instance, if you create a page that has 'the five latest events', you'll be using an Array of 5 'event' Records of ContentType 'events'.
Before we'll dive into the details, we'll give you a quick example of a simple ContentType, how it's stored, and how you can access it in templates to display on your site.
An Example: News items¶
In this example, we'll create a very simple ContentType for news items. Each
news item will have a title, an image, and some text. We'll also be using some
of the fixed Fields, like the slug
, the ownerid
and the various dates.
Note: If you've just installed Bolt, you might
not have the contenttypes.yml
-file yet. You will however have a
contenttypes.yml.dist
-file in that same folder. The first time
Bolt is run, the .yml.dist
-files will be automatically copied to
.yml
-files. If you wish to do some configuration before
you first run Bolt, just copy contenttypes.yml.dist
to
contenttypes.yml
yourself.
To add this ContentType, edit the file app/config/contenttypes.yml
, and add
the following to the bottom or top of the file:
news:
name: News
singular_name: Newsitem
fields:
title:
type: text
class: large
slug:
type: slug
uses: title
image:
type: image
text:
type: html
height: 300px
record_template: newsitem.twig
Note: This file is in the YAML format, which means that the indentation is important. Make sure you leave leading spaces intact.
This creates a new ContentType 'news'. Its name is 'News', and a single record is named 'Newsitem'. We've defined fields for 'title', 'slug', 'image' and 'text'. The 'record_template' defines the default template to use, when displaying a single record in the browser.
After you've saved the file and Refresh the Dashboard screen in your browser,
you'll be greeted by a warning that the Database needs to be updated. If we do
this, the new ContentType will be added to the database, with the fields that
we defined in our contenttypes.yml
file.
Tip: The Bolt backend is located at
/bolt
, relative from the 'home' location of your website.
When you go to Configuration > Check Database, the database will be updated, and you'll be given the option to add some "Lorem Ipsum" Records to the newly created ContentType. If you do this, and go back to the dashboard, you'll see your new ContentType with some example news items. Sweet!
Note:In the following examples we're going to tell you to make modifications to the default `base-2014` theme. This is actually a very bad practice, and if you're going to make your own theme, make a copy of the `base-2014` theme, and do your modifications in the copy.
To add a listing of these news items to the website, edit the twig template
theme/base-2014/index.twig
. Most likely, it'll contain an include for a
header and some other things. Add the following to the HTML-code, preferably
somewhere below the header section:
{% setcontent newsitems = "news/latest/4" %}
{% for newsitem in newsitems %}
<article>
<h2><a href="{{ newsitem.link }}">{{ newsitem.title }}</a></h2>
{{ newsitem.excerpt }}
<p class="meta"><a href="{{ newsitem.link }}">Link</a> -
Posted by {{ newsitem.user.displayname }}
on {{ newsitem.datecreated|date("M d, ’y")}}</p>
</article>
{% endfor %}
Most of the above example will seem pretty straightforward, but all of the specific template tags are explained in detail in the chapter about Content in templates.
When you refresh the front page of the website, you should see four news items
listed on the page. You can click the title to go to the news item on a separate
page, but you'll get an error. In the ContentType we defined the template as
newsitem.twig
, but it doesn't exist. Create the file in the theme/base-2014/
folder, and add the following HTML-code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{{ newsitem.title }}</title>
</head>
<body>
<article>
<h1><a href="{{ newsitem.link }}">{{ newsitem.title }}</a></h1>
{% if content.image!="" %}
<div class='imageholder'><img src="{{ newsitem.image|thumbnail(480, 480) }}"></div>
{% endif %}
{{ newsitem.text }}
<p class="meta"><a href="{{ newsitem.link }}">Link</a> -
Posted by {{ newsitem.user.displayname }}
on {{ newsitem.datecreated|date("M d, ’y")}}</p>
</article>
</body>
</html>
Tip: If you're curious about the different
{{ tags }}
in this bit of code, read the Template documentation.
In the frontend of the website, in your templates, all content is accessible as
an array. If you're accessing one record, it will be an array containing the
fields, taxonomies and metadata. If you're accessing a set of records, it will
be an array of arrays. I.e. {{ page.title }}
for the title of a page or {{ events.4.date }}
for the date of the fourth event in an array.
If you're building a template and are unsure of what a certain variable contains
or how the fields are named, use {{ dump(foo) }}
, where 'foo' is the name of
your record or array.
This is explained in detail in the section The structure of a Record.
Defining ContentTypes¶
The ContentTypes in Bolt are defined in the file app/config/contenttypes.yml
.
You can edit this file directly, or from within the Bolt interface under
Configuration > ContentTypes. Each distinct group of content can have its own
ContentType, to enable the user to store the content as needed. Fields can be
added later on, and settings can be changed, so nothing is set in stone.
The general structure of each ContentType is:
name:
option: value
option: value
option: value
..
The name
defines the name of the ContentType, and it should be a 'safe'
version of the name:
option below. Basically this means that it should be a
lowercase version, without any special characters. Like this:
pages:
name: Pages
singular_name: Page
..
cafes:
name: Cafés
singular_name: Café
..
The available options are:
Option | Description |
---|---|
name |
The name of the ContentType, as it should be shown on screen or in the browser. It should be plural, if possible. |
singular_name |
The name of one Record in the ContentType. This should be singular. For example, if the ContentType's name is 'Pages', this should be 'Page' |
slug (optional) |
This determines the slug of the ContentType, and therefore the URLs that are generated for this ContentType. When omitted, the slug will be automatically generated. |
singular_slug (optional) |
This determines the slug of a single record in this ContentType, and therefore the URLs that are generated for these records. When omitted, the slug will be automatically generated. |
description (optional) |
A short description of the ContentType. This will be shown on the overview screen in the right aside column. |
fields |
The fields that make up the content in this ContentType. See the Fields Definition section below for details. |
taxonomy |
An array listing the different taxonomies used by this ContentType. For example [ categories, tags ] . See the page on Taxonomies for details. |
relations |
An array listing the different relations available to this ContentType. See the page on Relations for details. |
record_template |
The default template to use, when displaying a single Record of this ContentType. The template itself should be located in your theme/foo/ folder, in Bolt's root folder. This can be overridden on a per-record basis, if one of the fields is defined as type templateselect . |
listing_template |
The default template to use, when displaying an overview of Records of this ContentType. The template itself should be located in your theme/foo/ folder, in Bolt's root folder. |
listing_records |
The amount of records to show on a single overview page in the frontend. If there are more records, the results will be paginated |
listing_sort |
The field used to sort the results on. You can reverse the order by adding a '-'. For example title or -datepublish . |
sort (optional) |
The default sorting of this ContentType, in the overview in Bolt's backend interface. For example -datecreated . Note that if your ContentType has a Taxonomy with has_sortorder , that the sort will be overruled by the Taxonomy's sorting. |
recordsperpage (optional) |
The amount of records shown on each page in the Bolt backend. If there are more records, they will be paginated. |
show_on_dashboard (optional) |
When set to false the ContentType will not appear in the 'Recently edited …' list on the dashboard page. |
show_in_menu (optional) |
When set to false the ContentType will show in a submenu instead of as a top level menu. Can also be set to a word or sentence to group ContentTypes under different menus. |
default_status (optional) |
Use this to set the default status for new records in this ContentType, i.e. published , held , draft or timed . |
searchable (optional) |
A boolean value to determine whether this ContentType should show up in search results. |
viewless (optional) |
When set to true , routes will not be set for the ContentType listing, or the records themselves. Useful for creating Resource ContentTypes. |
title_format (optional) |
Is used to determine the format of the title in the backend. For example if you have two fields for firstname and lastname you might put [ firstname, lastname ] here. |
icon_many (optional) |
A Font Awesome icon to be used in the sidebar for this ContentType. For example: fa:cubes |
icon_one (optional) |
A Font Awesome icon to be used in the sidebar for a single record of this ContentType. For example: fa:cube . |
The structure of a Record¶
Every record is an object, that contains the information of that record, as well as some meta-information and its taxonomy.
At the topmost level, it contains the following items:
Item | Description |
---|---|
id |
The unique identifying number of this record in the database, for this ContentType. Note: there are duplicate ids for records in different ContentTypes. For example, there can be a record with id 1 for Pages, and also a record with id 1 for News. |
values |
`An array with the values of this record. |
taxonomy |
An array (or NULL`) for the taxonomy of this record. |
contenttype |
`An array representation of the ContentType that this record belongs to, complete with the fields that the record should have. |
user |
`an array, containing information about the user, like the displayname, email-address, etcetera. |
The values contain the fields that are defined in the ContentType, together with a few other fixed fields. The fixed fields are:
Field name | Description |
---|---|
id |
The record's unique identifying number. |
slug |
The record's slug. Either generated automatically, or specified by the content editor. |
datecreated |
The timestamp of when the record was first created. |
datechanged |
The timestamp of when the record was last edited of modified. |
datepublish |
The timestamp when the record was published, or when it will be published. |
datedepublish |
The timestamp when the record was depublished, or when it will be depublished. |
ownerid |
The id of the user that last edited (or created) this record. |
status |
The current status of this record. Can be either published , depublished , held , timed or draft . |
If you're building a template and are unsure of what a certain variable
contains or how the fields are named, use {{ dump(foo) }}
, where 'foo' is the
name of your record or array. In most templates, {{ dump(record) }}
will work
as a generic fallback for whatever the name of your record is.
For detailed information on how to access the various fields and values in your templates, see the Template tags page.
Advanced: YAML Repeated Nodes¶
In order to make your ContentType definitions more compact, and consistent, you
can use YAML repeated nodes. Bolt has a special YAML key called __nodes
that
it will use only for repeated nodes, and not create a ContentType or table for.
These nodes then become selectable in a ContentType definition.
Each node is defined by an key_name: &node_name
with the fields then included,
and indented below.
## Defaults nodes. Does not create a ContentType
__nodes:
record_defaults: &record_defaults
title:
type: text
class: large
group: main
slug:
type: slug
uses: title
content_defaults: &content_defaults
image:
type: image
attrib: title
body:
type: html
height: 300px
group: content
template_defaults: &template_defaults
template:
type: templateselect
filter: '*.twig'
group: meta
In the above example, we have the record_defaults
node that defines title
and slug
fields, a content_defaults
node that defines the image
and body
fields, and a template_defaults
node that defines our template selector.
Using the above nodes we could simplify a default Pages
ContentType to look
like this:
pages:
name: Pages
singular_name: Page
fields:
<<: *record_defaults
teaser:
type: html
height: 150px
<<: *content_defaults
<<: *template_defaults
taxonomy: [ chapters ]
recordsperpage: 100
Couldn't find what you were looking for? We are happy to help you in the forum, on Slack or on Github.