Creating Posts, Custom Metadata, and Data in Wintersmith
In the first part of this mini-series I’ve introduced you to Wintersmith, one of the best Node.js-based static site generators in my opinion. I covered how to install and get started with Wintersmith and also discussed some features of Jade, its default templating system.
In this second installment, I’ll teach you how to create posts using the Markdown format, how to set custom Metadata, and also how to generate and deploy your static website.
Creating Posts
In the first part of this series, we’ve built our templates with Jade. Now it’s time to create some content for the site. By default, posts are written in Markdown rendered by Marked, though other renders are available as plugins.
Most developers seem to be familiar with Markdown, but if you aren’t, it’s very easy to learn. Many code editors either support it by default or via free extensions. There are many standalone Markdown editors out there, for example I use Mou on OSX and there is MarkdownPad on Windows. This post won’t go into the details of the specifics of Markdown but in case you need a place to start, I suggest you to take a look at this page.
Posts are placed in the contents/articles
folder. Each post is given its own directory which will be its SEO-friendly URL. For instance, our post for the Season 6 episode of Adventure Time! named “Breezy” was placed in a directory named articles/season-6-breezy
. Inside that directory there is our Markdown file for the post named index.md
.
Post Metadata
Each Markdown post can have metadata on top using the YAML format, similar to Jekyll’s Front Matter. No metadata is required but template
, title
, and date
. template
is the template that should be used to render the post, title
is the title of the post, and date
is the date it was posted. If template
isn’t specified, the post will not be rendered (which likely isn’t what you want). If title
and date
are unspecified, their values will receive defaults.
We are free to add any other metadata we want to. We’ll discuss this further in the custom metadata section below.
Wintersmith also allows us to specify metadata for posts using the JSON format via a JSON file in the contents directory. For more details on that, check the documentation.
Customizing Excerpts
Wintersmith lets us specify where it will end the excerpt within a post. This ensure that the excerpt does not exceed a specific length or ends in a logical spot. In order to specify the end of the excerpt, we have to place the following code within our Markdown post:
<span class="more"></span>
If we don’t specify this span
, Wintersmith will look for the first instance of an <h2>
or <hr>
. If none of these are present, the excerpt will contain the full HTML of the post which is not what you want. The excerpt is available via the intro
property on a page, as in our templates/partials/homepagemiddle.jade
file:
| !{ typogr(article.intro).typogrify() }
If we wanted to check that an excerpt was specified, we can use the hasMore
property of the page. You can learn more about how this works by examining the code of the page plugin.
Custom Metadata
Frequently, you’ll need to set your own metadata, either global to the site or local to a post/page. Let’s look at how this is done in Wintersmith.
Global Metadata
We can set any arbitrary metadata inside the config.json
file under the locals
object. For example, we can set a site name, description, and banner image in our sample site.
{
"locals": {
"url": "http://localhost:8080",
"name": "Adventure Time!",
"owner": "Brian Rinaldi",
"description": "Adventure Time is an American animated television series created by Pendleton Ward for Cartoon Network. The series follows the adventures of Finn, a human boy, and his best friend and adoptive brother Jake, a dog with magical powers to change shape and grow and shrink at will. Finn and Jake live in the post-apocalyptic Land of Ooo. Along the way, they interact with the other main characters of the show: Princess Bubblegum, The Ice King, and Marceline the Vampire Queen.",
"banner": "/assets/images/about.jpg"
},
...
These values are available anywhere in our site templates under a locals
object. For example, we use the values above within templates/partials/footer.jade
:
div(class="4u")
section
header
h2 What's this all about?
a(href="#",class="image featured")
img(src= locals.banner)
p= locals.description
It should be noted that these could also be referenced as banner
and description
without the locals
and it would work as well.
Per Post Metadata
As we discussed earlier, every post should have metadata set. This metadata can contain whatever arbitrary values we choose. For example, here’s the metadata for one of our articles (contents/articles/season-6-breezy/index.md
) where we set a shortdesc
and a banner
value.
---
title: "Breezy (Season 6)"
date: 2014-06-05 10:33:56
template: article.jade
shortdesc: Finn decides to get back into the dating game to help his wilting arm flower.
banner: /assets/images/breezy.jpg
---
We can access the shortdesc
value using the metadata
object within the page object. Here we’re using it inside a loop on templates/partials/footer.jade
:
- var i=0
- var articles = env.helpers.getArticles(contents);
each article in articles
-i++
if (i>2) && (i<8)
li
span(class="date")
!=moment.utc(article.date).format('MMM')
strong= moment.utc(article.date).format('DD')
h3
a(href=article.url)= article.title
p= article.metadata.shortdesc
Of course, we can also access these within our page output, as we do within contents/templates/article.jade
:
header
h2= page.title
p= page.metadata.shortdesc
Custom Data
Not everything in our site is going to be a post or metadata. Often we’ll have other types of data collections. For example, in our sample site, we have a collection of Adventure Time! characters with names, descriptions, and images. Rather than hardcode these values on a page, creating them as data allows us to reuse them throughout the site wherever we need and make their display flexible. Let’s see how this works.
Data in Wintersmith works similar to Jekyll collections in that it is file-based. Rather than placing a single JSON file into a predetermined folder, each object has its own file within whatever folder you choose under the contents
folder.
For example, in our sample site, contents/characters
contains a series of files, each with JSON data representing a character. Below is the contents of contents/characters/lsp.json
:
{
"description": "Lumpy Space Princess (LSP) acts like a bratty, apathetic, sassy, attention-seeking and willfully ignorant teenager, often texting on her phone.",
"image": "/assets/images/lsp.jpg",
"name": "Lumpy Space Princess"
}
This data is automatically read via the contents
object based upon the name of the folder, with each file becoming an object within the array. Each property within the file is available under the metadata
object. In our sample, we use this to output a list of characters on the home page:
each character in contents.characters
div(class="4u")
section(class="box")
span(class="image featured")
img(src= character.metadata.image)
header
h3= character.metadata.name
p= character.metadata.description
Generating and Deploying
Now that we’ve completed our project, it’s time to deploy it. But first we need to generate the static files that we have to upload to our server. To build our site, execute the following command:
$ wintersmith build
By default, this command will generate the files into a build
directory. However, we can specify a different path by using the -o
option. We can also force the clean of the build
directory before building by using the -X
option. For a full list of build options you can use the command wintersmith build --help
.
Conclusion
I think it’s pretty clear that Wintersmith offers a full feature set for a static site generator, allowing us to build complex static sites within the Node.js/npm ecosystem. Unfortunately, many of the topics discussed in detail here are not well covered in the limited project documentation.
The good news is that the source is all CoffeeScript, which is pretty easy to comprehend if you are a JavaScript developer. So, many of the details of how the project works can be learned by looking at the source code. In addition, there is a showcase of sites built with Wintersmith, many including source code, that can help you see how others have solved common tasks using the tool. While these are no replacement for a solid documentation, it should be able to get you where you need to go.
For additional samples of popular static site engines, check out my project on GitHub which includes not only this Wintersmith sample, but the same sample site built with Jekyll, Harp, and Middleman.