I use 11ty to publish articles like this one, but I also want to be able publish status updates, sort of like my own Twitter feed. Like a Twitter feed, I want each update to include a date and time when I wrote it. Unlike a twitter feed, I don't want each post to have a permanent url. Instead, I want to show the most recent updates on my home page, and I want to bump off the oldest status update every time I add a new one. This article explains how I did it.
Before I began, I had to decide what a status update
should include. For the time being, I want to keep things
very simple: a date and time, and a sentence or two
saying what I'm up to. Since status updates will be
simple, I can use a simple format:
markdown.
A markdown (.md
) file can be a paragraph,
several paragraphs, a list, and 11ty
will convert it into html
markup for me. It can
do the same with a simple note that consists of only
a sentence, which is often the case for microblogging.
And I change on a per-post basis. So if I
need something more advanced for a complicated note, I can
write it in
Nunjucks
syntax, giving me lots of markup flexibility.
The other thing I need for my updates is the date and time. 11ty helpfully uses the file creation timestamp to set the default date for a post. I can override it in front matter for an individual posts, but for simple updates, I probably won't need to.
With that settled, here's what I did to create my status update content with 11ty:
create a new directory for my status updates
First, I created a sub-directory inside src/
, my
11ty input directory.
I named the new directory status
.
turn off html file generation
While each post I write will be contained in a file in
my input directory, I didn't want 11ty to make individual
html
files in my
output directory.
So I needed to
turn off permalinks
for those files. Instead of doing that in each file's
front matter,
I did it for the
entire directory with a special data file.
In my newly created /status/
directory, I created a file
and named it status.11tydata.json
. Note that the root
name, status
, matches the directory name.
In that json
file, I added the following:
{
"permalink": false
}
That will be the default setting for all files in
the status
directory; it's the equivalent of adding
permalink: false
to each file's front matter section.
Even though 11ty won't create any files based on my
status update posts (nor links in any navigation lists),
it will still process the file, making it available to
collections.
creating a collection of status updates
That brings us to the next step: creating a collection
of status update posts in the
.eleventy.js
configuration file.
I could have made my collection based on a tag, but then
I would have had to add that tag to every status update post.
Instead, I used
getFilteredByGlob
,
which gets posts by directory. Here's what I added to .eleventy.js
:
eleventyConfig.addCollection('status', function(collectionApi) {
return collectionApi.getFilteredByGlob('src/status/*.*');
});
That gets all status updates posts, automatically sorted by date.
(The .eleventy.js
configuration file that I created for this
tutorial is shown at the bottom of this article in the
addendum.)
add the status update posts to the website
Now I was ready to add the status updates to my site. I use
Nunjucks as my 11ty template engine.
Nunjucks has a built-in for
loop that processes a collection
one post at a time. I wanted to put each status update in an
article element,
with the date of the post in a
time element.
Here it is in action, from my home page
template src/index.njk
:
<section class="statusUpdates">
<h1>what I'm up to at the moment</h1>
{% for item in collections.status) %}
<article>
<header>
<time datetime="{{ item.date.toISOString() }}">
{{ item.date }}
</time>
</header>
{{ item.templateContent | safe }}
</article>
{% endfor %}
</section>
The post is referenced as a javascript object. So the date
is shown as an attribute: item.date
. Note that, because
it's javascript, I can use javascript methods like
toISOString()
to supply a
machine readable date
for the
the datetime
attribute of the time
element.
The content of the post is item.templateContent
.
There is a buiit in nunjucks filter I'm applying,
safe
,
so that the html is rendered properly. If you want
to know the basics of templates and filters, take a
look at the
11ty page on layouts.
fine tuning the updates list
reverse the order of updates
That will show all status updates in chronological order.
But I want to show the newest status update at the top. To do
that, I added a built-in
nunjucks reverse
filter
to my for
loop. Right after the collections.status
variable,
I inserted a pipe character ("|"), then the filter name, reverse
.
The reverse
filter is a function that takes one parameter,
the part that comes before the pipe character. In my case, that
variable is an array of status update posts, which the filters
returns in reverse order. Here's my updated code:
<section class="statusUpdates">
<h1>what I'm up to at the moment</h1>
{% for item in collections.status | reverse) %}
<article>
<header>
<time datetime="{{ item.date.toISOString() }}">
{{ item.date }}
</time>
</header>
{{ item.templateContent | safe }}
</article>
{% endfor %}
</section>
limit the number of status updates in the list
The only problem now is that, as the number
of status updates grow, so will my home page.
I want to limit the number of posts that 11ty will process.
For that I have to create a
custom filter
and add it to my .eleventy.js
configuration file.
Recall from above that a filter is a function that takes a
parameter. The parameter I want to limit is a
collection
of posts. Since a collection
is an array
,
I can slice the array and return the slice. Here's what I
added to .eleventy.js
:
eleventyConfig.addFilter('limit10', function(arr) {
return arr.slice(0, 10);
});
(Again: the .eleventy.js
configuration file that I created for this
tutorial is shown at the bottom of this article in the
addendum.)
You can chain filters by adding them to the statement, each separated by a pipe character:
<section class="statusUpdates">
<h1>what I'm up to at the moment</h1>
{% for item in collections.status | reverse | filter %}
<article>
<header>
<time datetime="{{ item.date.toISOString() }}">
{{ item.date }}
</time>
</header>
{{ item.templateContent | safe }}
</article>
{% endfor %}
</section>
Now 11ty will get the collection of status update posts;
reverse their order; slice it so that only the most recent
ten are left; and finally run a loop, assigning the posts
one by one to the item
variable. In each loop, it will
output the post's date and the content in standard html
markup for display on my home page.
a small bit of style
To separate updates, I added a border between each item by adding the following code to my site's stylesheet:
.statusUpdates > article {
border-top: 1px solid gray;
}
adding my first status update
I just created a new file in my status
directory called
microblog-launch.md
with just eight words:
I just created a personal twitter-like microblog.
And voilà, on my home page, under the headline "what I'm up to at the moment" is my first status update.

what this doesn't do
This is not really micro-publishing, in the sense that I have to create a file with the note. So I have to be at my laptop to enter a status update. In the future, I might try to figure out how I might update my status from a mobile device, perhaps using a form of some sort.
If I do that, I might add the ability to include a location when I'm posting from somewhere other than home. Or not. I do value my privacy.
why not just use Twitter?
You might be wondering, why not just open a Twitter account? Because I want more control over where, when, and how to publish my thoughts. Plus, I really hate Twitter. Not as much as Facebook, but still. Not a fan.
addendum: the configuration file (edited)
Here is the .eleventy.js
configuration file to go along with
this article:
module.exports = function(eleventyConfig) {
eleventyConfig.addFilter('limit10', function(arr) {
return arr.slice(0, 10);
});
// Filter status update file names using a glob
eleventyConfig.addCollection('status', function(collectionApi) {
return collectionApi.getFilteredByGlob('src/status/*.*');
});
// 11ty defaults
return {
dir: {
input: 'src'
}
};
};