Creating a basic blog with Eleventy and Netlify CMS completely from scratch
Tags: webdev, netlify, tutorial, beginners
Published: 2020-04-24 23:46:18

[New video version available!](https://www.youtube.com/watch?v=WEApDhZMAL4)

[Eleventy](https://www.11ty.dev/) is a powerful and wonderfully simple static site generator. [Netlify CMS](https://www.netlifycms.org/) is a simple, open-source content management system that makes adding, editing and deleting posts and other content a breeze. Today I'm going to show you how to create a basic blog using eleventy and Netlify CMS, entirely from scratch- no boilerplates, no templates, no nothing. Be aware that this tutorial will create an absolute bare-bones text blog for you to build upon- I'm not even adding CSS! Let's get to it.

##Part 1: Setting up

###Requirements:
  - Node.js and NPM installed
  - Git installed
  - A Git provider such as GitLab or GitHub
  - A free Netlify account
  
First, there're some things we need to get set up before we begin coding. First, create a git repository on your preferred service (I use and recommend [GitLab](https://gitlab.com/)) and clone the empty repo to your computer.

Enter the project root with your terminal and install eleventy by typing `npm install @11ty/eleventy --save-dev`. Once that is done, install luxon by typing `npm install luxon`. Luxon is the only special addition here and will allow us to format readable dates in our posts.

Create a new folder in the project's root and name it `_includes`. This folder will contain templates that our blog will use to render pages. Create another new folder in the root directory called `images` and another inside of that called `uploads`. Netlify CMS will use this folder to store images uploaded to your site. Create *yet another folder* in the root of your project called `admin` and finally, a folder in the root named `posts`. Once that's done, we're ready to start coding!

Create a file in the root of the project named `.eleventy.js` and write this in:

```
module.exports = function(eleventyConfig) {
  eleventyConfig.addPassthroughCopy('images')
  eleventyConfig.addPassthroughCopy('admin')

  const {
    DateTime
  } = require("luxon");

  // https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
    eleventyConfig.addFilter('htmlDateString', (dateObj) => {
      return DateTime.fromJSDate(dateObj, {
        zone: 'utc'
      }).toFormat('yy-MM-dd');
    });

    eleventyConfig.addFilter("readableDate", dateObj => {
    return DateTime.fromJSDate(dateObj, {
      zone: 'utc'
    }).toFormat("dd-MM-yy");
  });

};

```
The `eleventy.js` file is a configuration file. The `addPassthroughCopy` lines tell Eleventy to include those folders and their contents in the generated site. The rest is just some JavaScript to make the dates in the postslist more readable.

Now create another folder within `_includes` named `layouts`. Within that folder we can create a new file called `base.njk`. The `base` file forms the basis of every page on our website. We'll add add `<head>` elements and a site header here. Any element that should appear on *every single page* should reside in `base.njk`. Let's add the following to the file:
```
<html>
  <head>
  	<title>Eleventy + Netlify CMS from scratch</title>
  </head>
  
  <body>
    <h1>
      Eleventy + Netlify CMS from scratch
    </h1>
    {{ content | safe }}
  </body>

</html>

```
Like I said: Bare bones. Note the line that says `{{ content | safe }}`: this is where page content for other pages will be rendered.

Now, create a file named `index.njk` at the **root of your project**. This will be your homepage. Add the following to `index.njk`:

```
---
layout: layouts/base.njk
permalink: /
---
Hello! Welcome to the Eleventy + Netlify from scratch homepage.
```

Our Nunjucks (`.njk`) files will accept html, markdown and more. Between the sets of hyphens lies our page's **frontmatter**. This data tells Eleventy how to handle our page and provides other information as we need it to. `layout` tells it which template to use, in this case `base.njk` whilst `permalink` tells it what the URL for this page will be (in this case, `/`, or the homepage). Anything under the hyphens will be used as the main content on the page. You can use text, markdown or html to create the body. In this case I simply use a line of text.

Now open your terminal back up and run this command:

`npx eleventy --serve`

If your website doesn't open automatically, browse to `localhost:8080` and you should see our homepage!

![Your first page!](https://dev-to-uploads.s3.amazonaws.com/i/ydbbq89wuhd1wks1prmt.png)

##Part 2: Blog posts

Let's add a page that will be used for blog posts next. In the `_includes/layouts` folder, add a new file called `post.njk`. We'll come back to this in a minute, but first let's create a basic blog post. In the `posts` folder, create a file called `posts.json` and add the following:

```
{
	"tags": "posts"
}
```

This will ensure that every post in this folder has the correct tag attached. Now add a file in the `posts` folder named `my-first-post.md`. Even though this is a markdown file, we will still add some frontmatter here. Add the following code to `my-first-post.md`:

```
---
layout: layouts/post.njk
title: My first post
description: The first post on the Eleventy + Netlify CMS from scratch blog
date: 2020-04-18
featuredImage: /images/uploads/image1.jpeg
---
Hello, here is the body of the post.
```
Let's take a look at our frontmatter:

- `layout` tells this post which template to use, in this case `layouts/post.njk`
- `title` is the title of the post
- `description` is a short description of the post
- `date` is the date the post was written
- `featuredImage` is an image for the post. Drop any image you want into `images/uploads` and use its path- mine is `image1.jpeg`

Again, anything underneath the frontmatter will be the blog post content. Note that we won't be creating posts like this in future since the Netlify CMS will take care of it for us!

Now that our post is ready, lets render it. Add the following to `_includes/layouts/post.njk`:

```
---
layout: layouts/base.njk
---
<h2>{{ title }}</h2>
<h3>{{ date | readableDate }}</h3>
<img src="{{ featuredImage | url }}" alt="{{ featuredImage }}"></img>
<p>{{ content | safe }}</p>

```

Our post page uses the `layouts/base.njk` template and renders blog post data in its body. We use double brackets `{{  }}` to refer to data in the post's frontmatter. In the case of `my-first-post.md`, the `{{ title }}` will end up being `My first post`, which we provided in the markdown file. Eleventy will create a blog post page for every markdown file in the `posts` folder. Neat!

We now have a working blog, but no way to see the posts. Let's fix that by adding a new file in the `_includes` folder called `postslist.njk`. This file will use a `For Loop` to create a list of all of our posts. Add this to the file:

```
<ul>
  {% for post in postslist %}
    <li>
      <strong>
        <a href="{{ post.url | url }}">{{ post.data.title }}</a>
      </strong>
      -
      <time datetime="{{ post.date | htmlDateString }}">{{ post.date | readableDate }}</time>
      -
      <span>{{ post.data.description }}</span>
    </li>
  {% endfor %}
</ul>

```

With the above code, Eleventy searches for every post in a variable called `postslist` and renders the title, date and description of each. To create the `postslist` variable, create a new file in the root of the project called `posts.njk`:

```
---
layout: layouts/base.njk
permalink: /posts/
---
{% set postslist = collections.posts %}
{% include "postslist.njk" %}
```

This file populates the `postslist` variable with every `post` that has the tag `posts`. Earlier we created `posts.json` to take care of the tagging for us! If all is well, you can now browse to `localhost:8080/posts/` to see your list of posts! Feel free to add a couple more posts as `.md` files in the `posts` folder to see how they show up.

The very last thing to do with the blog portion of our website is to go back to `index.njk` at the project root and add this line at the bottom:

```
{% set postslist = collections.posts %}
{% include "postslist.njk" %}
```

The `includes` keyword basically embeds the file into the current page- we're rendering `postslist.njk` inside the homepage, which now shows your post list as well!

![The postlist](https://dev-to-uploads.s3.amazonaws.com/i/b2r7idrit5spor2bwcjq.png)

![Our post page](https://dev-to-uploads.s3.amazonaws.com/i/cj8v3h0ltiyy9ysj7kbh.png)

Whew! We're done with this part. Go over to your terminal and push the changes to your Git repository.

##Part 3: Netlify CMS

Now it's time to set up the Netlify CMS. First we'll have to get our website hosted with Netlify.  Login to Netlify and click `New site from Git`. Login with your Git provider (I use GitLab) and authorize Netlify to access your repositories. Select your repo from the list. Under `Basic build settings`, set the `Build command` to `npx eleventy` and the `Publish directory` to `_site`. Click `Deploy site`.

![Setting up on Netlify](https://dev-to-uploads.s3.amazonaws.com/i/1ncumoqf0ico545dkm6h.png)

After your deploy completes, you will see a link (ending with `.app`) that will take you to your live blog. 

![The live blog](https://dev-to-uploads.s3.amazonaws.com/i/x1npbj5vvhzjmkdpecnu.png)

In the menu above your site URL, click `Identity`. 

On the Identity screen, click `Enable Identity`. After it's enabled, click `Settings and usage` and find `Services`. Click `Enable Git Gateway`. Sign in again if prompted.

![Identity Options](https://dev-to-uploads.s3.amazonaws.com/i/zefmp178sl9jklju0v3y.png)

In the above steps we have successfully created a live website with Netlify. We also enabled Netlify's Identity feature which will take care of authentication and accounts for us. Finally, we enabled Git Gateway, which is an API that will let the Netlify CMS commit changes to the git repository without needing to re-authenticate or give anybody access to it directly.

Back in your project, create `index.html` inside the `admin` folder. In this file we will add some basic HTML [provided by Netlify](https://www.netlifycms.org/docs/add-to-your-site/#app-file-structure) which loads the CMS UI and authorization widget:

```
<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Content Manager</title>
  <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
</head>
<body>
  <!-- Include the script that builds the page and powers Netlify CMS -->
  <script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script>
</body>
</html>
```

Create another file in the `admin` folder named `config.yml`. .YML files rely on accurate indentation. Be sure to use **spaces to indent, not tabs**! First, we will enable the Git Gateway API by adding the following:

```
backend:
  name: git-gateway
  branch: master # Branch to update
```
Now we'll point to our `images/uploads` folder, which is where pictures uploaded from the CMS will be stored, however since Eleventy stores our static site in the `_site` folder, we also need to add a public folder too. Add these lines underneath `branch: master`, making sure the lines are **not** indented:

```
media_folder: "_site/images/uploads"
public_folder: "/images/uploads"
```

The last thing to do is to create a **collection** for our posts. We'll use the `config.yml` file to create this collection, and **it will match the frontmatter we set in our post markdown files** earlier. Add this under the `media_folder:` line we just created:

```
collections:
 - name: "posts" 		#The name of the collection and should match our posts.json file's tag
   label: "Posts" 		#The name of the collection on the CMS itself
   folder: "posts" 		#The folder that our blog posts will be loaded from and saved to
   create: true 			#Tells the CMS that new posts can be created
   slug: "{{year}}-{{month}}-{{day}}-{{slug}}"	#this sets the URL for the post
   fields:
      - {label: "Layout", name: "layout", widget: "hidden", default: "layouts/post.njk"}
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Description", name: "description", widget: "string"}
      - {label: "Date", name: "date", widget: "date", default: ""}
      - {label: "Post Body", name: "body", widget: "markdown"}
      - {label: "Featured Image", name: "featuredImage", widget: "image"}
```

Let's explore the `fields` section. Notice that each field matches the frontmatter of our `my-first-post.md` file. Let's also explore each part of each line:

- `label` is the name of the field that will appear in the CMS
- `name` is the name of the field, it must match the frontmatter exactly
- `widget` tells the CMS which widget to display from a selection. `string` is a single line of text and others are available, listed [here](https://www.netlifycms.org/docs/widgets/). `markdown` is generally used for the post content.
- `default` sets a default value for the field

A full explanation of the collections section can be found [here](https://www.netlifycms.org/docs/add-to-your-site/#collections). A collection doesn't have to be for posts only- you can add one for individual pages or even individual datasets. That is beyond the scope of this article, however.

The last thing to do is to return to `layouts/base.njk` and add this line and add it before the closing `</head>` tag:

`<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>`

In the same file, add this before your closing `</body>` tag:

```
<script>
    if (window.netlifyIdentity) {
      window.netlifyIdentity.on("init", user => {
        if (!user) {
          window.netlifyIdentity.on("login", () => {
            document.location.href = "/admin/";
          });
        }
      });
    }
  </script>
```

Great news: You're pretty much done! Save, commit your changes and push your project. Wait for the deploy to complete (make sure your commit says `Published` in Netlify under `Production deploys`) then go to your website's url. Add /admin to the url and you'll be transported to the login screen! Log in and you'll be taken to the Netlify CMS backend where you can create and edit posts and upload media! Please be aware that posts added via the CMS can take a few minutes to appear after you submit them. Netlify will re-deploy your site when a new post is added!

![The Netlify CMS!](https://dev-to-uploads.s3.amazonaws.com/i/vwlqom5t4ehxw28h3tof.png)

This tutorial was a very quick and crude integration of Eleventy and Netlify CMS, however it should help you to understand *how* the two connect, rather than using a boilerplate or template blog, which can easily be too cluttered from the get-go. I hope that this tutorial was helpful in showing you how you can build a simple blog with a back-end editor with very little time and effort. I encourage you to play around with frontmatter, different collections and pages. Please reach out to me on Twitter @KoaBrook with any questions or feedback, as well as to show you your attempts!

![Eleventy + Netlify CMS Blog from scratch](https://dev-to-uploads.s3.amazonaws.com/i/ipog6aou1lzgjq6freah.png)

## Resources
- [11ty.dev](https://11ty.dev)
- [Netlify CMS](https://www.netlifycms.org/)
- [Eleventy Base Blog](https://www.netlifycms.org/): Provided the starting steps for my journey with Eleventy!