© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
A. LibbyBeginning Eleventy https://doi.org/10.1007/978-1-4842-8315-8_4

4. Creating Templates

Alex Libby1  
(1)
Belper, Derbyshire, UK
 

So far, we’ve created our initial site, set up the structure, and added data, but everything looks like we’ve thrown it on a page and that it needs structure! No problem, we can fix that by using templates. These will help us to lay out the content properly, so it’s easy for customers to read.

We can use any one of several different tools for this job – this might be anything from Handlebars to Nunjucks, or even just standard HTML. This chapter will explore how templates work in Eleventy and begin to create something for our demo site. Let’s start first with a quick overview of how templates work in Eleventy.

Understanding How Templates Work in Eleventy

Remember back in Chapter 1, when we talked about the different elements that make up an Eleventy site?

One of the critical elements is templates – in many cases, we might think of these as a way to format content, but templates have a unique context in Eleventy.

In our project, we’ll be using a mix of Nunjucks and Markdown files – templates in Eleventy are known as layouts as we use them to wrap content. If one were to mention the word “template,” this is a more generic term related to all content files. I know – it can get a little confusing, mainly as we can mix and match the various supported options, but that’s partially down to the flexibility (and power) of Eleventy! For this reason, I’ve elected to stick with using Nunjucks and Markdown – this is purely my personal preference, but the same principles will apply to other languages supported in Eleventy.

When creating layouts in Eleventy, there are several key features that we use to make up layouts. We’ve already touched on a few, namely:
  • Pagination

  • Collections

  • Permalinks

  • Setting dates for posts to override the default date set

Irrespective of how we format a layout, there are two questions we should ask ourselves when using them: Where do we store any layout, and how many layouts do we need?

In answer to the first, the location is essential – we should store all layouts within the _includes folder. Keeping them in this folder may not be an issue for a small site, but anything more than just a few pages and it will soon become unmanageable! However, we can specify a subfolder and reference it when setting the layouts property in the front matter for each template file.

A more important topic is that of layout architecture – we might think we only need one, but that isn’t necessarily the correct answer. Let me explain.

For a small site of just a few pages, yes, using a single layout may suffice. However, it does limit one’s options regarding how content is displayed – you will want the same header and footer across the site. For example, if you have multiple posts, you may have elements that should only be on post pages but not on other pages like About or Contact. An excellent example of this is a “back to main index” link or “next post/previous post” navigation links; these would be ideal in a layout for posts but not necessary on other pages.

The best approach is to build a base layout that has elements common to all pages. We can then create a layout that inherits this base layout when needed, such as blog posts or book product pages. This technique is called layout chaining and is a vital part of creating any layout - let’s put this theory into practice and begin to make the layouts for our site, starting with our base layout.

Creating Layouts for Our Site

When it comes to creating layouts, I would recommend one piece of advice – follow the KISS principle, or “keep it simple, s…” (yes, you get the idea!).

It’s tempting (and, indeed, possible) to go over the top when it comes to creating layouts – the principle of layout chaining (which we talked about just now) means you could chain multiple layouts together in theory. Tying together more than two layouts in this way is bad practice, though, as it creates a significant dependency and will be hard to manage and debug in the future.

It’s better to keep to as flat an architecture as possible this keeps it clean, makes it easier to manage, and reduces the risk of odd effects happening when inheriting features from a parent layout.

With this in mind, we’re going to build three layouts in total – the main one will be base.njk, from which we will create a post layout for post pages and a page one for all other pages. Let’s dive in and take a look at setting up the base template in more detail.

Building the Base Template

We will keep this very simple for this first layout – it will contain the relevant meta tags for now, along with the header and footer (the latter two as imported components). We can then use this as a basis for the other two layouts later in this chapter.

Demo – Creating Base Layout
To set up the base.njk layout, follow these steps:
  1. 1.

    First, go ahead and stop any development server you have running for Eleventy – switch to the Node.js command prompt and hit Ctrl (or Cmd)+C to exit the process.

     
  2. 2.

    We need to set up three components for use with our layout – one of them we will source from the code download and the other two we will create from scratch. Go ahead and create a new subfolder called components within the _includes folder.

     
  3. 3.

    Next, we need a copy of the socialmedia.njk file from the code download available with this book – go ahead and extract a copy of this file and store it in the components folder from step 2.

     
  4. 4.

    Now switch to your editor and create a new file, called footer.njk in the components folder. Add this code to it:

     
<footer>
  <div class="copyright">
    <p>{{ sitedata.copyright }}</p>
  </div>
  {% include "../components/socialmedia.njk" %}
</footer>
  1. 5.

    The second component we will create is header.njk – for this, create a new file, and add this code:

     
<header>
  <a href="{{ '/' | url }}">
    <img src="../../img/logo.png"/>
    <h1 class="home">{{ sitedata.title }}</h1>
  </a>
  <ul class="nav">
    {%- for entry in collections.all | eleventyNavigation %}
      <li class="nav-item{% if entry.url == page.url %} nav-item-active{% endif %}">
        <a href="{{ entry.url | url }}">{{ entry.title }}</a>
      </li>
    {%- endfor %}
  </ul>
</header>
  1. 6.

    Save and close both component files. With the components now in place, we can create our layout – add this code to a new file, saving it as base.njk in the layouts folder:

     
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title or sitedata.title }}</title>
    <meta name="description" content="{{ description or sitedata.description }}">
  </head>
  <body>
    {% include "../components/header.njk" %}
    <main>
      {{ content | safe }}
    </main>
    {% include "../components/footer.njk" %}
  </body>
</html>
  1. 7.

    Save this file – we will recompile code in the next exercise, once we’ve created the next layout and updated all of the pages to use it.

     

With us completing that exercise, we now have achieved one major milestone – we now have a header and footer present, which we can use across our site! The styling will come in a later chapter, but for now, there are a few key features we should explore in more depth from this exercise, so let’s take a closer look at the code in more detail.

Breaking Apart the Code

While the last exercise wasn’t a particularly long one, we’ve covered some key points the basic premise being that we’ve created the main template for the entire site and added in some extra components as dependencies for this template. So what did we achieve?

We kicked off by extracting a copy of the social media icons component from the code download. This file contained the markup required to display the SVG icons in our footer; while it is a Nunjucks-formatted file, it doesn’t contain anything special, over and above standard SVG/HTML markup for our icons.

Things become more interesting in the header and footer components the latter is where we start to use the Nunjucks templating functionality to import the title value from sitedata.json as {{ sitedata.copyright }}. We include this value in double curly braces, which tells Eleventy to compile that value from sitedata.json, and display it on screen, as shown in Figure 4-1.
Figure 4-1

An example of data imported from sitedata.json

We can see from Figure 4-1 that Eleventy does not include any framework markers in the final compiled markup, unlike other frameworks. It means the only way you will have to confirm it has worked is to change the value in sitedata.json and recompile the code.

In header.njk, we step things up a bit much of what we used is standard HTML markup, but there are a few key points of note. In the second line, we use a | (or pipe symbol) to signify an “OR” statement we grab either the slash or whatever we set in the pathPrefix value in .eleventy.js to concatenate and normalize the URL path to each page. At the same time, we pull in the sitedata.title value from the sitedata.json file and wrap H1 tags around the value.

In the next block, the code might look a little more complex, but in essence, we grab all of the data collections before iterating through each in a for...endfor block, looking for eleventyNavigation entries, such as this one:
eleventyNavigation:
  key: Home
  order: 0

If we find any, we then build a list element that contains a link to the text of the menu entry (in this case, Home) and the URL to that entry (which will be /, or root). At the same time, we added some extra styling classes that we will use in a later chapter.

We then moved on to the most critical part building the base.njk template itself. Most of this is standard HTML markup, but we used a couple of Nunjucks features - see the or statement for title or sitedata.title, for example? This says “go grab the title property from markup if it doesn’t exist, take it from the sitedata.json file instead.” If neither exists, it will be blank, but hopefully, we won’t ever get to that point!

We also used {{ content }} as a placeholder to tell Eleventy where to put any content that consumes this layout. The addition of the safe in this filter is to force Eleventy to double-escape properties so that hackers can’t try to execute scripts in this block.

To learn more about this double-escaping feature, please refer to https://www.11ty.dev/docs/layouts/#prevent-double-escaping-in-layouts.

Phew – that was some review: we’ve now built out the first part of our templating code for the site! We’ve focused on using Nunjucks for this, as it’s the author’s personal preference; we could easily have used other tools. Before we move on to adding the remaining layouts, let’s take a moment to consider what other options we might have used on our site.

Choosing the Right Tools

So far, we’ve worked with Nunjucks, HTML, and Markdown to produce our content and layouts. This combination is perfectly acceptable and suits our needs perfectly. Now that I’ve created some layouts using Nunjucks, it is an excellent time to ask yourself two questions:
  • How do I feel about using Nunjucks if I were to push this site into production?

  • Would this combination work for me, or is there a different combination that would suit my needs more?

It might seem odd to ask these questions at this stage, but there is a good reason for this: Eleventy supports a range of different templating languages, so we are not limited in what we can choose.

Don’t forget that Eleventy supports any one of ten different templating languages for layouts, so plenty of choices are available. We have so far used Nunjucks, HTML, and Markdown. This combination is one of several we could use – we might prefer to use Handlebars instead of Nunjucks or even work with pure JavaScript. This last choice would seem ironic, given that Eleventy prides itself on not being a JavaScript framework! With that in mind, two tips can help:
  • It’s an almost dead cert that we will need to use HTML and CSS, so this will take care of a good proportion of what will become your layout. The templating language will be primarily for inserting data at compile-time, so work with whichever templating language suits your requirements. You might want to use several languages at the same time, but bear in mind that we need to set a dataTemplateEngine property in the .eleventy.js file, and trying to set multiple entries at best will cause problems, or at worst, is not supported! It’s better to stick with one choice at a time and test it – if one doesn’t work, then there are others we can use.

  • When creating templates, we don’t have to convert everything in one go – Eleventy is perfectly happy with converting piecemeal. It’s an excellent opportunity to try out different languages – if you don’t already have a predetermined choice (e.g., Handlebars), then you can try converting some files to use Handlebars. If that doesn’t suit your requirements, you can switch to an alternative without having committed too much in terms of time or resources.

  • If you decide to use a particular combination, then make sure you are clear on the syntax to use – most of the languages supported by Eleventy use a similar syntax, so it can become confusing if you are not careful! I would recommend getting a syntax highlighter or checker plugin for your editor to help with keeping you on the right path.

If you decide to use a particular combination in Eleventy, don’t worry if you trip up at some point – you won’t be the first or the last! I am sure that GitHub will be a good place to stop for help (see the Appendix for more sources). The developers of Eleventy have also produced a list of common pitfalls that are worth taking a look at if you find yourself struggling with an issue when using Eleventy.

The list of pitfalls is available at https://www.11ty.dev/docs/pitfalls/.

Okay – let’s crack on: we still have two more layouts to set up! We’ve already done most of one of them (post.njk) from a previous exercise, so there will only be a couple of tweaks required for that layout. That we will come to shortly, but for our next layout, let’s take a look at page.njk for all nonpost pages in our site.

Updating Content Pages

The layout we will use for content pages will seem significantly more manageable than the previous one – primarily as we are inheriting much of the markup from base.njk and only need to create a slot to render content on each page. We can add to it later, but it will at least keep content separate from the post pages, which we will cover in a later exercise.

Demo – Creating The Page Layout
To set up the page layout, follow these steps:
  1. 1.

    First, shut down the Eleventy server – we’re changing layout content, so we need to stop the server so Eleventy can recompile any changes we make when we restart the server.

     
  2. 2.

    Switch to your text editor, then in a new file, go ahead and add this code:

     
---
layout: layouts/base.njk
---
{{ content | safe }}
  1. 3.

    Save it as page.njk in the layouts folder.

     
  2. 4.

    Next, we need to update the appropriate pages to reference our new layout – first, open 404.md, then add in the layout entry after the title reference, as indicated:

     
---
title: ...
layout: layouts/page.njk
  1. 5.

    Save and close the file. Go ahead and repeat the previous two steps with the remaining files – they are contact.njk, archive.njk, index.njk, and about.njk.

     
  2. 6.

    For the remaining two files, tags-list.njk and tags.njk, we need to do something slightly different – when you edit these files, add this instead:

     
---
layout: layouts/page.njk
---
  1. 7.

    Make sure you save and close all of the files once you have made the changes.

    Don’t forget that the order of entries in the front matter is not critical: if you see other items such as title first, slot the layout entry in afterward.

     
  1. 8.

    As one last step, we can now remove the original navigation template logic from index.njk – we’re inheriting this from the base.njk file.

     
  2. 9.

    We’re almost done – we need to recompile our code, so revert to your Node.js command prompt session that you had open from step 1. Then at the prompt, enter npm run serve and hit Enter to recompile the code.

     
  3. 10.

    Switch to your browser – go ahead and browse to http://localhost:8080. If all is well, we should see something akin to that shown in Figure 4-2 when clicking on the About Me link.

     
Figure 4-2

The updated page template in use on the About page

This last exercise was more straightforward than the previous one, but an important one – we now have a template set up that is suitable for nonpost pages. It is a simple one, but the critical point here is that we have something that we can extend with extra content at a later date. The basic principle of how the layout works is still the same as the base layout – let’s take a quick look at the code in more detail.

Understanding the Code Changes

We’ve made good progress with adding our layouts; the changes we’ve made cover most pages, with only the posts layout left to complete (in the next exercise). You may be wondering a little as to what the black lines are in some of the screenshots. Don’t worry: I’ve not gone mad with a thick black marker; it’s the SVG images from the footer before styling!

We will fix this in Chapter 6 when I take you through the steps required to make our site more presentable.

Leaving styling aside for a moment, we started by creating the page.njk layout, which inherits from the base.njk we created in an earlier exercise. We kept this one simple, as most of the functionality we need (for now) is already in the base layout; creating the page layout allows us to keep different types of content separate in our site.

We then moved on to updating the remaining pages that we created to consume this new layout before recompiling the code and previewing an example of our work on the About page of our site.

Restarting the Eleventy server isn’t always necessary – I’ve added it as a step in most exercises, but you may find you can get away without the need to stop and restart it. Strictly speaking, you should do this for instances such as changing layouts, but I’ve found cases when it hasn’t always been necessary. Rebooting will certainly cause no harm; you may want to try it first to see if it is indeed required.

Okay – let’s move on to the final layout: this last one already exists, but we still need to make some changes to it. I’m talking about the post layout – let’s dive into the following exercise to see what we need to update to get it ready for use.

Updating the Post Layout

Okay – we’ve created two out of the three layouts; there is one more we need to prepare, which is for our blog post pages.

This one, post.njk, is a little different, as we already created most of this layout in earlier exercises. However, there is one change we need to make, so let’s get to making that change as part of our next exercise.

Updating The Post Template
To complete the layout for posts, follow these steps:
  1. 1.

    First, stop the Eleventy development server if it is already running by hitting Ctrl (or Cmd)+C in the Node.js command prompt that is running the server.

     
---
layout: layouts/base.njk
---
  1. 2.

    Go ahead and save, then close the file.

    It’s worth noting that post2.md already has the entry for post.njk, but nothing is showing; making this change will align with the remaining pages.

     
  1. 3.

    We’re almost done – we need to recompile our code. Revert to the Node.js command prompt that you had opened from step 1, then at the prompt, enter npm run serve and hit Enter to recompile the code.

     
  2. 4.

    Switch to your browser – go ahead and browse to http://localhost:8080/posts/my-second-post/. If all is well, we should see something akin to that shown in Figure 4-3, which shows an extract of the post2 post with a header and footer. In this instance, I’ve gone on ahead and added a Contact page and eleventyNavigation using techniques we’ve covered in the book.

     
Figure 4-3

The updated post template, with a header and footer

Wow – that was a short exercise: it shows that we don’t always need to work through lengthy steps to achieve something! This change was only a small one, but still an important one; it highlights an essential point about layout inheritance, so let’s pause for a moment to review the changes in more detail.

Breaking Apart the Changes

So what did we do in that last exercise?

We started by stopping the Eleventy server as we were making changes to the layouts used on our site. We then moved on to creating a new layout that inherits the base layout created in the previous exercise; this contained a {{ content | safe }} entry to act as the placeholder for any content that consumes this template.

We then moved on to updating the remaining nonpost pages to use this template; in most cases, we simply added in the layouts: layouts/page.njk entry as the second item in the front matter. For the tag files, the position was slightly different, but the reference is still the same. As the final step for this exercise, we recompiled the code and previewed the results using the about page as our example.

There is one crucial point, though the use of {{ content | safe }}. We’ve used this in both the base.njk and page.njk layouts you might ask if this is necessary or how it works when we use a layout that inherits from another.

It’s a good question: we can use both layouts independently, which is fine. However, when it comes to inheriting a template, the key to this is this:
  • Let’s assume we have a file called about.njk (as we do), which consumes the page.njk layout.

  • The page layout file deliberately does not contain the header or footer markup; instead, it inherits the base.njk template.

  • It means that once compiled, all of the content in about.njk effectively replaces the page.njk file - the {{ content | safe }} entry in that layout is a placeholder for content from about.njk.

If we are chaining layouts as we are here, then that {{ content ... }} entry translates directly to the same {{ content... }} entry in base.njk. I’ve put together a simple illustration to show you how it works in Figure 4-4.
Figure 4-4

Layout inheritance used in our site

A more detailed version of this is available in the code download as a PDF – look for “layout inheritance.pdf.”

The best way to think of it is to use the same principle as Russian dolls - remember them? One sits inside another, sitting inside one more, and so on. You get the idea!

Right – on we go: we’ve now reached a point where all of the layouts we need are in place; we’ve updated most of the files to use them. We need to make a few more changes before we can mark this stage as complete; we need a 404 page, plus some extra pages to take care of RSS feeds and a site map. These will complement what is already on the site; they are easy enough to set up, so let’s dive in and take a look.

Updating the Rest of the Site

So far, we’ve updated the core parts of our site – we’re at a stage where we have the basic skeleton in place and working well.

This last part is about adding features that will help complement the site – there are a fair few changes to make, which we will do over a series of exercises. These all contain helpful techniques for creating layouts, so let’s crack on and get the rest of the files set up on our site, beginning with setting up a site map file for our site.

Setting Up a Site Map

For our first exercise in this last batch of changes, we’ll be adding in a site map – they are an underrated tool for helping search engines crawl every corner of a website. Fortunately, building an XML site map in Eleventy (11ty) is super quick and easy, so let’s dive in and take a look at the steps required in more detail.

Creating a Site Map
To complete the various updates left for our site, follow these steps:
  1. 1.

    The first update is to stop the Eleventy host server, as we need to change the layout and content files. Switch to your Node.js command prompt, and press Ctrl (or Cmd)+C to stop the server if it is running.

     
  2. 2.

    Next, we will create our site map – for this, go ahead and create a new file, then add in this code, saving it as sitemap.xml.njk at the root of our project area. We’ll do this in blocks, starting with the front matter and opening XML tags:

     
---
permalink: /sitemap.xml
eleventyExcludeFromCollections: true
---
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns:="http://www.sitemaps.org/schemas/sitemap/0.9">

The urlset line in this step must be one continuous line without the line break shown in text; otherwise, this will cause an error.

  1. 3.

    This block takes care of building the actual URL displayed in the map:

     
  {% for page in collections.all %}
    <url>
      <loc>{{ site.url }}{{ page.url | url }}</loc>
      <lastmod>{{ page.date.toISOString() }}</lastmod>
      <changefreq>{{ page.data.changeFreq if page.data.changeFreq else "monthly" }}</changefreq>
      <priority>{{ item.data.sitemapPriority | default(0.8) }}</priority>
    </url>
  {% endfor %}
  1. 4.

    We then need to close it by adding this tag:

     
</urlset>
  1. 5.

    Save and close the file. Switch to a Node.js command prompt, then change the working folder to our project area if it is not already there.

     
  2. 6.

    At the prompt, enter npm run serve and hit Enter to recompile the code.

     
  3. 7.

    Switch to your browser – go ahead and browse to http://localhost:8080/sitemap.xml. If all is well, we should see something akin to Figure 4-5.

     
Figure 4-5

An extract of our site's site map file

Adding this feed file is a relatively quick change to make, but an important one – we can tell search engines such as Google where to find our content.

I’m not advocating putting out our localhost version; this is something you would do for the production version of your site, but you get the idea! That aside, we’ve covered a couple of valuable points, so let’s pause to review the code in more detail.

Exploring the Changes Made

Creating a site map in Eleventy is trivial most of the work required to render content is taken care of by the {% for... %}…{% endfor %} block in our code.

We kicked off by adding two properties in the front matter, which set a dedicated URL for our site map and tells Eleventy not to include this file when iterating through all site data. We then created a for...endfor block, inside which we iterate through each page in the site (except, of course, for those explicitly excluded in the front matter).

This block creates dedicated nodes for each valid page in our site; each contains four properties: loc, lastmod, changefreq, and priority. These are standard XML tags for feed pages; loc sets an absolute URL that points to the given page. This one is compulsory, but for the others, we can specify any one of these parameters:
  • lastmod – Sets a date (in yyyy-MM-dd format) to indicate when the page was last updated.

  • changefreq – This string value relates to how often this page is generally updated (we can set any of these values: always, hourly, daily, weekly, monthly, yearly, or never).

  • priority – This is a decimal value (ranging from 0.0 to 1.0) that indicates the priority of this page in comparison with other pages on your site.

There are a couple of interesting features in use inside this block:
  • We use interpolation to pull in and set various properties from the sitedata.json file – it’s something we’ve already used in multiple places throughout this chapter, and of which you will no doubt see more later in this book.

  • We also use an | (or pipe) symbol and an Eleventy if...else condition.

This latter point is of particular interest. The syntax is specific to Eleventy, but the principle is the same if one value doesn’t exist, we use the other.

There is a slight difference: we use the fallback value in the first or statement if the first specified value doesn’t exist. For the second type of statement, we fall back to the second value, but only if the first value is not a match. It’s essential to understand this distinction, as you might have (quite rightly) thought we could use a pipe symbol, but this wouldn’t result in the right effect!

Although having a site map will help with the likes of Google, there is one more step we could (and should) add – that is a robots.txt file. This file should be present on any site and might look like this:
User-agent: *
Disallow:
Sitemap: https://<YOUR-URL-HERE>/sitemap.xml

Adding the robots.txt file will help Google understand what files should or should not be indexed – granted, it might take time for Google to find your site, but hey: there is a limited amount one can do to get any advantage if working with search engines!

Okay – let’s move on: the next part of the site left to build is an RSS feature. It’s an old technology (having been around 20-plus years) but still valid; let’s dive in and take a look at this in more detail.

Adding RSS Feeds

RSS feeds have been around for over two decades as a technology, first appearing on the scene back in 1999. They may be an old technology, but still, a great way to get content to a reader who subscribes to get updates directly from the site.

We will add two feed files for this next exercise – one in XML format and the other in JSON. A few steps are involved, so we will go through it as a two-part exercise, starting with the XML feed.

Adding An rss Feed – Part 1: XML Format
To add the XML feed, follow these steps:
  1. 1.

    Fire up a Node.js command prompt, then change the working folder to our project area.

     
  2. 2.

    Go ahead and stop the Eleventy server, then at the prompt, enter npm install @11ty/eleventy-plugin-rss and press Enter to install the Eleventy RSS plugin.

     
  3. 3.

    Next, crack open .eleventy.js, and add this line after the last const statement at the top of the page – leave a line blank after it and the start of the module.exports block:

     
const pluginRss = require("@11ty/eleventy-plugin-rss");
  1. 4.

    With the import now in place, we need to call in the plugin. Scroll down to just inside the start of the module.exports block. Below the last .addPlugin() reference, add this:

     
eleventyConfig.addPlugin(pluginRss);
  1. 5.

    Next, create a new folder called feed at the root of our project area.

     
  2. 6.

    Inside this folder, create another new file, and this time, add the following code, saving it as htaccess.njk:

     
---
permalink: feed/.htaccess
eleventyExcludeFromCollections: true
# For Apache, to show `{{ sitedata.feed.filename }}` when browsing to directory /feed/ (hide the file!)
DirectoryIndex {{ sitedata.feed.filename }}
  1. 7.

    The next file we need to add is feed.njk – this is one of two that will provide a feed service from our site. We need to add a good chunk of code, so we’ll do it in sections, starting with the opening tags:

     
---
# sitedata comes from _data/sitedata.json
permalink: "{{ sitedata.feed.path }}"
eleventyExcludeFromCollections: true
---
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns:="http://www.w3.org/2005/Atom">
  <title>{{ sitedata.title }}</title>
  <subtitle>{{ sitedata.feed.subtitle }}</subtitle>
  1. 8.

    This section takes care of adding the correct URL, updated stats, author, and ID based on what is set in sitedata.json:

     
  {% set absoluteUrl %}{{ sitedata.feed.path | url | absoluteUrl(sitedata.url) }}{% endset %}
    <link href="{{ absoluteUrl }}" rel="self"/>
    <link href="{{ sitedata.url }}"/>
    <updated>{{
      collections.posts |
      rssLastUpdatedDate }}
    </updated>
    <id>{{ sitedata.feed.id }}</id>
    <Author>
      <name>{{ sitedata.author.name }}</name>
      <email>{{ sitedata.author.email }}</email>
    </author>
  1. 9.

    This final block iterates through all of the posts in reverse order before rendering various details on screen:

     
    {% for post in collections.posts | reverse %}
      {% set absolutePostUrl %}{{ post.url | url | absoluteUrl(sitedata.url) }}{% endset %}
      <entry>
        <title>{{ post.data.title }}</title>
        <link href="{{ absolutePostUrl }}"/>
        <updated>{{ post.date | rssDate }}</updated>
        <id>{{ absolutePostUrl }}</id>
        <content type="html">{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) }}</content>
      </entry>
    {% endfor %}
</feed>
  1. 10.

    Save and close the file. Switch to a Node.js command prompt, then change the working folder to our project area if it is not already there.

     
  2. 11.

    At the prompt, enter npm run serve and hit Enter to recompile the code.

     
  3. 12.

    Switch to your browser – go ahead and browse to http://localhost:8080/feed/feed.xml. If all is well, we should see something akin to that shown in Figure 4-6.

     
Figure 4-6

The completed feed file for our site, rendered in a browser

Phew – that was some exercise! We still have the JSON version to add: go and get a drink and take a breather first. When you’re ready, come back, and we will carry on with the second part of this exercise.

Adding An rss Feed – Part 2: json Format
To add the JSON feed, follow these steps:
  1. 1.

    We already have the RSS plugin installed, so we can go directly to adding the JSON version of our feed file. For this, go ahead and create a new file, saving it as json.njk in the feed folder.

     
  2. 2.

    Next, go ahead and add in this code – as before, we have a sizable chunk to add, so we will do it in sections starting with the front matter:

     
---
# sitedata comes from _data/sitedata.json
permalink: "{{ sitedata.jsonfeed.path }}"
eleventyExcludeFromCollections: true
---
  1. 3.

    Next, add this block – it takes care of setting some common properties, based on what is in sitedata.json:

     
{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "{{ sitedata.title }}",
  "language": "{{ sitedata.language }}",
  "home_page_url": "{{ sitedata.url }}",
  "feed_url": "{{ sitedata.jsonfeed.url }}",
  "description": "{{ sitedata.description }}",
  "author": {
    "name": "{{ sitedata.author.name }}",
    "url": "{{ sitedata.author.url }}"
  },
  1. 4.

    Immediately below it, add this block – it iterates through all of the posts in reverse order (except for those excluded in the front matter). We set various properties, based on what was set at the top of this file:

     
  "items": [
    {%- for post in collections.posts | reverse %}
  {%- set absolutePostUrl %}{{ post.url | url | absoluteUrl(sitedata.url) }}{% endset -%}
    {
      "id": "{{ absolutePostUrl }}",
      "url": "{{ absolutePostUrl }}",
      "title": "{{ post.data.title }}",
      "content_html": {% if post.templateContent %}{{ post.templateContent | htmlToAbsoluteUrls(absolutePostUrl) | dump | safe }}
  {% else %}""{% endif %},
      "date_published": "{{ post.date | rssDate }}"
    }
    {%- if not loop.last -%}
    ,
    {%- endif -%}
  {%- endfor %}
  ]
}
  1. 5.

    Save and close the file. Switch to a Node.js command prompt, then change the working folder to our project area if it is not already there.

     
  2. 6.

    At the prompt, enter npm run serve and hit Enter to recompile the code.

     
  3. 7.

    Switch to your browser – go ahead and browse to http://localhost:8080/feed/feed.json. If all is well, we should see something akin to that shown in Figure 4-7.

     
Figure 4-7

An extract from the completed JSON feed

Both feed files look different (and we would expect them to, given they are two different formats, after all). However, if you look closer, two principles are used in both versions – interpolating placeholder values and iterating through an Eleventy collection. These are both critical parts of Eleventy, so let’s pause for a moment to review the changes made and understand what happens in more detail.

Understanding What Happened

Adding the second RSS feed to our site is more manageable this time around, as we have already installed the core RSS plugin for Eleventy. However, we still had to make a few changes, so let’s explore these in more detail.

We started by creating a new file called json.njk, into which we added the usual front matter (a dedicated permalink, followed by excluding it from all Eleventy collections). Next came a block that set several properties; all of these (except the version, which is standard JSON) came from the sitedata.json file.

We iterated through all of the posts available in collections, in reverse order, to pull out various properties for display in our file. The properties we collated are id, url, title, and content_html (if present, or date_published if not available). As part of this, we used the absoluteUrl function from the RSS plugin to ensure that we render all URLs as absolute links, not relative. We then rounded out the exercise by running the by-now-familiar recompile process before previewing the results in a browser.

Okay – time to move on to the last change for this chapter: handling invalid URLs. This process is an essential staple for any website; otherwise, we could end up displaying something… let’s say “less than customer-friendly” to our viewers! Not something we want to do, so let’s crack on and find out how we can a 404 page to our Eleventy site.

Handling Invalid URLs

Hands up – how many times have you entered a URL, only to find it’s a duff link, and up pops a message? I suspect the answer for many is likely to be “countless” – indeed, if I had a dollar for every time I had this, I would be on an exotic island somewhere, with no need to work, and where I could enjoy paradise! But I digress.

Bringing things back to reality, I am talking about creating a 404 page, a staple for any website. We’ve already created the basic 404 page earlier in this book, so it’s time to wire it up on our site. This is a straightforward process involving making changes in the .eleventy.js file – let’s dive in and explore what we need to change in more detail.

Setting Up a 404 Page
To wire in the 404 page created earlier, follow these steps:
  1. 1.

    We need to create a 404 page for our last file – this step is a little more complex. First, we need to add one more property into the front matter of 404.md, so go ahead and open the file, then add this:

     
eleventyExcludeFromCollections: true
  1. 2.

    Next, crack open .eleventy.js, and add this line after the last const entry at the top of the file:

     
const fs = require("fs");
  1. 3.

    Now scroll down to the function starting with this line:

     
eleventyConfig.addFilter('htmlDateString', (dateObj)
  1. 4.

    Below the closing }); of that function, enter a new line, then add in this block:

     
eleventyConfig.setBrowserSyncConfig({
  callbacks: {
    ready: function (err, browserSync) {
      const content_404 = fs.readFileSync(
      '_site/404/index.html');
      browserSync.addMiddleware("*", (req, res) => {
        res.writeHead(404, {
          "Content-Type": "text/html;
          charset=UTF-8" });
        res.write(content_404);
        res.end();
      });
    },
  },
  ui: false,
  ghostMode: false,
  open: true
});
  1. 5.

    At the end of the block, enter a new line after the closing brackets and before the return { statement; this will make it easier to read.

     
  2. 6.

    We have one more step: install the plugin we added at the top of this file. Save and close the file.

     
  3. 7.

    Switch to a Node.js command prompt, then change the working folder to our project area if it is not already there.

     
  4. 8.

    At the prompt, enter npm install fs, and press Enter – this will install the fs package referenced by the code we added in step 2.

     
  5. 9.

    At the prompt, enter npm run serve, and hit Enter to recompile the code.

     
  6. 10.

    Switch to your browser – go ahead and browse to http://localhost:8080/foo. If all is well, we should see something akin to that shown in Figure 4-8.

     
Figure 4-8

Testing the 404 page for our site

Excellent – we have a working 404 page, which will kick in anytime someone finds they type a URL that doesn’t resolve correctly. We’ve set up the basic page for now, but this doesn’t mean we should stop here: we should take it further and develop it into something more unique for our site. As an example, take a look at the list provided by the Search Engine Journal website at https://www.searchenginejournal.com/404-page-examples/211154/ there are some great examples there!

Exploring the Changes Made

Adding a 404 page is a staple for every website in an ideal world, customers should never see this page, but this won’t always be the case! Displaying a 404 page means that we can at least manage things gracefully and not lose customers who drop out of the site.

We’ve already added the 404.md page earlier in the book, so we only had to add one more change before wiring it into our site, which was the eleventyExcludeFromCollections property. This property we set to true; this prevents it from appearing in any collection that we might reference (and thus end up displaying it in results).

We then switched to the .eleventy.js file to add a reference to the fs (or FileSystem) NPM package and an override for the BrowserSync plugin used by Eleventy. This override tells Eleventy to write out the contents of the 404 page on screen any time we get a 404 error returned by the browser.

We finished with installing the fs plugin before completing the by-now-familiar recompilation process and previewing the results in our browser.

Summary

Our journey into the world of Eleventy templates began with a quick overview of how templates work in Eleventy. We learned that although we might refer to them as templates, they are layouts in the context of Eleventy.

We then began constructing the base layout for our site. At the same time, we also explored two critical questions around making sure that we choose the right combination of tools to use – it’s essential to get this right. Eleventy is flexible enough to allow us to change the combination, should we find that our first choice doesn’t suit our needs.

Next up, we updated the content pages and changed the post layout; this got us to a stage where the core pages now have layout/template support in place. We then rounded out the chapter with some additional changes, such as adding a site map and a 404 page, so that our site structure is now largely complete.

We’re making good progress with constructing the site, but there is still some way to go! For the next stage, we will move away from building layouts and focus our attention on adding or configuring options within Eleventy. Here, we can go to town on fine-tuning the overall experience and start adding our own features to Eleventy stay with me, and I will reveal more in the next chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.238.82.77