Craft CMS: The (very) basics of templating

A brief introduction to templates in Craft CMS.

Craft gives you full control of your site's HTML in the form of templates that are saved as files.

Add a file called index.html to your craft/templates folder, load the root domain of your site, i.e., in your browser and the contents of that file will be shown. Now create a new folder within your craft/templates folder called news and add another file called index.html. Back in your browser load and the contents of that new file will be shown. That is the (very) basics of templating.

What makes Craft's templating so powerful and flexible though is a) it's template engine, Twig, and b) how it handles routing.

For this post I'll focus on the routing.


Routing simple means how Craft recognises the URLs you enter in your browser (the request) and determines what to do with them. There are a number of checks Craft makes when a request comes in which are outlined in the documentation. As you'll see, the basic example we used above is #6 in that list - Does the URI match a template?

So far we have templates matching the following requests:

  • /
  • /news/

Next you might want to create a template that will display an individual news story. Create a file called entry.html within your craft/templates/news folder. If you now load in your browser you'll again see the contents of that template.

That's not exactly what you want though. Your site visitors will never be requesting that URL. Instead you'll be wanting to publish news stories with URLs such as:


The last segment in those URLs is known as a 'slug'. Slugs are unique identifiers for your news stories, in this case generated from the news story's title.

What we need to do is tell Craft that whenever it receives a request matching the format /news/{slug} it should route it to the /news/entry.html template. We can do that via the admin interface.

Creating a new section

Browse to the settings page, click "Sections" under Content, and then hit the "New Section" button.

Our new section's name will be "News". Craft will generate a handle (again this just another name for a unique identifier) based on that name. We can keep the Section Type as Channel for this example, and the "Entries in this section have their own URLs" option can also be left checked. If you're interested you can read about the different section types available in the documentation.

It's the next two fields that are important for this example.

Within the "Entry URL Format" field we need to enter our desired URL format for our news story entries. In our case that's news/{slug} which just happens to be the default anyway.

Within the "Entry Template" field we need to enter the path to the template we created earlier, which is news/entry.html (including the .html is optional).

Let's save that new section and add some entries.

Creating some entries

If you now go to the "Entries" tab and hit the "New Entry" button (select News if you have more than one section to choose from) you'll see the "Create a new entry" screen.

Fill in as many fields as is required but before hitting the Save button, click the settings tab and make a note of the slug that has been generated.

Repeat this a few times so you have a number of published news stories.

Viewing your entries

We're now ready to view the entries in our template.

If you look again at the Routing page in the documentation, specifically at #4 Is it an entry request? When Craft comes across a request that matches what was entered in a section's "Entry URL Format" field, it loads that section's entry template but it also "makes the entry's content available to the template via a pre-populated entry variable".

Go back to the news/entry.html template and we'll add that entry variable so that we can see the difference our requests are making. Simply add the following HTML tag and variable to your template:

<h1>{{ entry.title }}</h1>

Now browse to and you should see the title of your news story. Change the slug to one of the others you noted and the title should change.

That's it. We've created some (very) basic templates and seen a couple of examples of Craft's routing checks in action.

Hiding templates

One problem with our current setup is that it's still possible to directly access our news/entry.html template simply by browsing to Try it. As you'll see, the {{ entry.title }} variable it contains isn't parsed this time because there is no news entry with the slug 'entry'.

To avoid this Craft lets you specify some templates as being 'hidden' or not directly accessible by requesting them in your browser. To do this you simply prefix them with an underscore so let's rename the template to news/_entry.html. You'll also need to edit your News section and update the "Entry Template" field.

Now if you try to access in your browser Craft will return a 404 message.

Where next?

There's more to Craft's routing than just these simple examples. You should definitely experiment with dynamic routes.

Twig is the primary reason Craft' templating is so flexible and the Twig Primer is a great place to start.