Nice Permalinks In Eleventy AND Nice Filenames in Obsidian
A while ago [[eleventy-change-permalinks|I made a post]] about how to change (part of) the permalink that Eleventy generates from the filename. Since I am using Obsidian as my blog editor I had a little problem:
- On the one hand: I wanted to have nice, readable filenames - with spaces and everything - so that I can link between entries more easily
- On the other: If I use readable filenames - with spaces and everything - they get not slugified correctly, meaning that spaces in the filename are just urlencoded instead of replaced by dashes, etc. (see [[The Closed List|this post]] for an example)
- On yet another, secret, third hand: Without a title in the frontmatter, posts do not get a title in my blog
The Solution For Hands One And Two
We replace the permalink
of our blog.11ydata.js
:
"permalink": "{{page.filePathStem.slice(5).replace(page.fileSlug, '')}}{{page.fileSlug|slugify}}/index.html"
This is a little convoluted as Eleventy doesn't seem to expose the path without the filename. So we have to cut the file name off and then re-add a slugified version.[1]
The Solution For The Secret Third Hand (that is actually many hands...)
My blog is based on the eleventy-base-blog so I had to adjust my postlist.njk
so that it understood to look for a title in the fileSlug
. Here I had the additional challenge that I already had changed the logic for older posts that were written for a different blog system. Especially my DailyDogo series relied on the fact that if no title was set, then the first 20 characters of the body of a post were used. Changing this to the filename (fileSlug
) yielded a lot of posts named "dailydogo".
To solve this, I came up with the following solution: We only use the filename, if it includes a space. This means that all other files will use the old logic, i.e. use a title if given, otherwise use the first 20 chars.
Here's how that looks:
{%- css %}.postlist { counter-reset: start-from {{ (postslistCounter or postslist.length) + 1 }} }{% endcss %}
<ol reversed class="postlist">
{%- for post in postslist | reverse %}
<li class="postlist-item{% if post.url == url %} postlist-item-active{% endif %}">
<a href="{{ post.url }}" class="postlist-link">
{% if post.data.title %}
{{ post.data.title }}
{% elseif " " in post.data.page.fileSlug %}
{# if filename has spaces (probably written in Obsidian use that as title #}
{{ post.data.page.fileSlug }}
{% else %}
{{ post.rawInput | striptags | truncate(20) }}
{% endif %}
</a>
<time class="postlist-date" datetime="{{ post.date | htmlDateString }}">{{ post.date | readableDate }}</time>
</li>
{%- endfor %}
</ol>
We need a similar solution for the individual post template. Here's the important part:
{% if post.data.title %}
<h1>{{ title }}</h1>
{% elseif " " in page.fileSlug %}
{# if filename has spaces (probably written in Obsidian use that as title #}
<h1>{{ page.fileSlug }}</h1>
{% endif %}
We also need to update our feed[2]:
{%- for post in collections.posts | reverse %}
{%- set absolutePostUrl %}{{ post.url | htmlBaseUrl(metadata.base) }}{% endset %}
<entry>
<title>
{% if post.data.title %}
{{ post.data.title }}
{% elseif " " in post.data.page.fileSlug %}
{# if filename has spaces (probably written in Obsidian use that as title #}
{{ post.data.page.fileSlug }}
{% else %}
{{ post.rawInput | striptags | truncate(20) }}
{% endif %}
</title>
[...]
And [[search-in-eleventy|the JSON-Feed we use for our search]]:
"items": [
{%- for post in collections.posts | reverse %}
{%- set absolutePostUrl %}{{ post.url | htmlBaseUrl(metadata.base) }}{% endset %}
{
"id": "{{ absolutePostUrl }}",
"url": "{{ absolutePostUrl }}",
"title": "{% if post.data.title %}{{ post.data.title }}{% elseif " " in post.data.page.fileSlug %}{{ post.data.page.fileSlug }}{% else %}{{ post.rawInput | striptags | truncate(20) }}{% endif %}",
[...]
The pattern should be clear by now. Anywhere where we had used post.data.title
or title
depending on the context, we now want to use post.data.fileSlug
or page.fileSlug
with a similar nunjucks if
construct.
I had to change a bunch of other places:
post.njk
[...]
{% if title %}
<h1>{{ title }}</h1>
{% elseif " " in page.fileSlug %}
{# if filename has spaces (probably written in Obsidian use that as title #}
<h1>{{ page.fileSlug }}</h1>
{% endif %}
<ul class="post-metadata">
[...]
home.njk
- this is used for normal "pages" that aren't posts (like [[garden]]). I added a title here in the first place which in turn meant removing some hardcodedh1
s
---
layout: layouts/base.njk
---
{% if title %}
<h1>{{ title }}</h1>
{% elseif " " in page.fileSlug %}
{# if filename has spaces (probably written in Obsidian use that as title #}
<h1>{{ page.fileSlug }}</h1>
{% endif %}
{{ content | safe }}
And there you have it! Now we can have nice permalinks that are based on the filename and those filenames do not need to be "permalink" friendly (i.e. all small caps, dashes instead of spaces, etc.) and we still can adjust this on an individual basis by specifying a permalink and/or a title in the yaml frontmatter of individual posts.
-
← Previous
DailyDogo 1317 🐶 -
Next →
DailyDogo 1318 🐶