Setting up TILs in Pelican
Inspired by Simon Willison, I started writing TILs (today I learned). I find it incredibly helpful to write as I code, but most of that writing has never left my private notebooks. TILs are my attempt at documenting and sharing my day-to-day learnings in case they might help others. The focus on learning also feels less daunting than writing blog posts.
I wanted to support TILs on my blog as a separate set of posts with their own listing page. Thanks to Pelican’s incredible flexibility, this was quite easy!
Following these steps requires using a custom theme. I personally use a custom theme (forked from the builtin simple theme) precisely so that I can easily make these sorts of customisations.
Reconfigure your archives
Start by renaming archives.html
to posts/index.html
(relative to your theme’s templates
directory).
Edit the loop over dates
in posts/index.html
to exclude articles tagged til
:
% for article in dates if 'til' not in article.tags|default([]) %} {
Add the new path to DIRECT_TEMPLATES
, the corresponding line of my pelicanconf.py
now looks like:
= ['index', 'posts/index'] DIRECT_TEMPLATES
… because I don’t have tag or category pages yet. Disable the original archives page:
= '' ARCHIVES_SAVE_AS
It should be working as it was before, but we’re now able to add a few more listings in the same way!
Create the TILs listing
Copy posts/index.html
to tils/index.html
, and edit the for loop to only include articles tagged til
(note that the not
from before is missing):
% for article in dates if 'til' in article.tags|default([]) %} {
Add the new path to DIRECT_TEMPLATES
in your pelicanconf.py
:
= ['index', 'posts/index', 'tils/index'] DIRECT_TEMPLATES
You probably also want to link to the listing from your nav bar. For my theme, that’s done by adding a line to the <nav>
tag in my base.html
template:
<a href="{{ SITEURL }}/tils/">TILs</a>
Hack article URLs
This is my favourite part! At this point, you should have two working listings, but TIL article URLs will be the same as any other article. Pelican determines the URL and output location of an article by calling format
with the article’s metadata on strings ARTICLE_URL
and ARTICLE_SAVE_AS
. That means we can implement a tiny string class with a custom format
to dynamically set the URL of TILs to tils/{slug}
and of posts to posts/{slug}
!
Simply include the following in your pelicanconf.py
:
class ArticleUrl(str):
def format(self,tags=[],**kwargs): return ('tils/' if 'til' in tags else 'posts/') + super().format(**kwargs)
= ArticleUrl('{slug}/')
ARTICLE_URL = ArticleUrl('{slug}/index.html') ARTICLE_SAVE_AS
Update invoke task
If you’re using live reload via the invoke livereload
task, you’ll need to update your task definition to include nested HTML files in your theme:
- server.watch('{}/templates/*.html'.format(theme_path), lambda: build(c))
+ server.watch('{}/templates/**/*.html'.format(theme_path), lambda: build(c))