2026-11-02 01:10:00
A few people have reached out to me to ask how I did X, or Y with my site, so I thought I'd talk about the customisations I've made to this site, and how they work.
Firstly, this site runs on Pure Blog, a CMS that I've been building over the last year or so. As it's matured, I've added features that allow more advanced users to do clever things without having to fiddle with the core platform. This means that people generally shouldn't have to fork the project and should continue to get all the new goodness as I release it.
This site is no different. I haven't done anything clever that Pure Blog can't do out of the box - everything is documented so by reading the docs and using a bit of creativity, you can do quite a lot with this plucky little CMS. I'll link out to the appropriate docs as we go through this post.
Ok, so what customisations have I made? This is going to be a fairly long post, so I'll list them here with links to each header so you can jump around and read the parts that interest you.
If you want to see specific code examples for any of these customisations, feel free to contact me.
I have three custom post types on this site - notes, links, and books. Notes are used as short-form social media type posts, links are links to other blog posts that I've enjoyed, and books are short reviews of the books I read.
Each has their own layout and in the case of notes, they have a different view on the homepage too. To do this I've created a custom post-list.php partial, but we will come to that later.
I could just use the default post type for all these posts, but I prefer to have a customised UI at the back-end for each. Here's what books and links look like in my editor:
Notes are a little different as I use a custom page for them that only I can access. This looks more like a social media post window than a blog post window:

Read the custom post layout docs ➡
I like to think of hooks as little tripwires that are set to go off when certain conditions are met. For example, something happens when an image is uploaded, or a new post is published. They're extremely useful and I have a number of them on this site:
on_filter_content): Scans rendered content and encodes the site email address into hexadecimal HTML entities to protect against scrapers. This has been pretty effective at reducing spam - I wrote more about this feature in this post.on_filter_post):mastodon_url in post frontmatter when saving via the admin interface so the Mastodon card at the bottom of every post continues to work.on_image_uploaded): Automatically resizes images exceeding 2560px width whilst maintaining aspect ratio, also converts them to lossless WebP, and cleans up original unoptimised files.on_post_published): Automatically crossposts all published post types to Fosstodon via the Mastodon API.mastodon_url into the post's frontmatter which is then used for the Mastodon card at the bottom of every post.on_og_image_font): Makes dynamic Open Graph image generation to use my custom font.Beyond custom post types, Pure Blog lets you drop PHP files into content/includes/. These can either override default pieces of the site (like navigation or post footers), or serve as entirely bespoke standalone pages, like my quick-publish notes screen, or the terminal 404 page.
Here's a full list of the templates and partials used on this site:
post-list.php (partial): This replaces the default post-list.php and adds post-type filter buttons, preserving query parameters across pagination. It also displays notes in full, while other post types show only the title and excerpt.post-meta.php (partial): A customised version of the default post-meta.php file from Pure Blog. On top of the default tag list and post pagination, this version adds the obfuscated "Reply by email" button, a client-side Mastodon conversation card displaying live stats (favourites, boosts, replies) as well as a link to the post on Fosstodon, Pure Comments integration, and a subscription call-to-action.discover.php (template): Dedicated discovery hub combining Pure Blog's full-text search with an alphabetical, weighted tag cloud showing post frequencies.sitemap.php (template): An interactive metro map that lists all of the pages on this site. There's also an option to see the pages as a list.social.php (template): My quick-publish admin screen for composing and publishing short-form note posts.100.php (template): Dashboard for tracking the 100 Days to Offload challenge streaks in batches of 100 posts.masthead.php (partial): This replaces the default masthead template in Pure Blog. It adds a custom layout, as well as 404 handoff ($is404) to render the custom 404.php template without modifying core Pure Blog files.404.php (template): A fun interactive terminal-styled 404 page with custom commands that include goats!random-post.php (template): Endpoint that resolves and redirects visitors to a randomly chosen published post.Read the layout partials docs ➡
I've replaced the default feed with one that allows for filtering on post type. So one feed file, 5 feeds - one for each post type, and a fifth for everything.
My custom feed template allows you to visit /feed/ for everything, or /feed/[post-type] (e.g. /feed/books) for the posts of that particular type. This custom feed file lives in /content and I then used .htaccess redirects to redirect the default /feed URL to /content/feed.php.
All the feed URLs are available here.
I use a self-hosted instance of Sendy to send out email "newsletters" whenever I publish a new post. These emails always contain the entire post, so people can read my content from their inbox if they wish.
Because I write notes much more frequently than long-form posts, I let readers choose what they receive: everything, long-form content only, or notes only.
To make that work without sending people through clunky third-party forms, I wrote a custom server-side handler (content/subscribe-handler.php). When someone submits the form on the subscribe page, the handler:
This not only helps segregate the emails people receive, but it has also had a dramatic effect on spammy sign ups. Which, if you've ever run a newsletter, you will know is a common problem.
Pure Blog allows you to add your own PHP helper functions for all kinds of things. On my site, I only have 1 function defined:
render_star_rating(string $rating) which transforms fractional score strings in my book posts (e.g. "4/5") into accessible star glyph strings (e.g. "★★★★☆"). I just think that "★★★★☆" looks far nicer in a post than "4/5".
But how is this star rating accessible? Well, it's rendered on the front-end like this so screen readers can parse it:
<span class="star-rating">
<span class="star-rating" aria-label="4/5 ★★★★☆">★★★☆☆</span>
</span>
Read the custom functions docs ➡
I don't do anything magical with the design on this site. I use the Victor Mono font, and around 850 lines of CSS, which I've added to the custom CSS field within settings. Combined with the custom masthead, post-list and post-meta files above, it gives me everything I need to customise the site from the default look to what you see now.
I have a custom theme palette that I've defined too, also in settings. The colours used can be found at the bottom of my colophon.
Read the design customisation docs ➡
One of the most powerful things about using a static site generator is the ability to use data files. With data files you can have a structure data file, like YAML, that contains repeated data, which can then be looped through on the front-end to render content.
I really wanted Pure Blog to be able to support data files, so I added support very early on. Personally, I use two data files on this site:
data/blogroll.yml which is then used to render my blogroll page.data/projects.yml which is used for my projects.Data files are fantastic as they reduce the amount of repetitive code you have to write. Instead of typing div, after div, after div manually, you write your div once, then loop through it with a data file and Pure Blog does the rest.
.htaccess rules
The final thing I customise is my .htaccess file. There's a number of things I do to the standard Pure Blog .htaccess file to either redirect URLs, or protect various locations:
/admin/ access to specific allowed IP addresses./blog/* and /categories/* URLs to clean root and /tag/* routes that Pure Blog uses./feed.xml, /social-feed, /social-feed.xml, /rss, /blog.rss, etc.) to /feed or /feed/notes to make sure the feed URLs from various versions of this site don't break.This ended up being an even longer post than I anticipated, but hopefully it shows just how much you can bend Pure Blog to your will, by design.
None of this requires hacks to the core code, or maintaining your own fork. Everything you see here is achieved using Pure Blog as designed: settings, custom CSS, hooks, custom layouts, and partials. Because all these files live inside /content, /config, and /data, I can upgrade Pure Blog the moment a new release drops without worrying about overwriting my site's bespoke features.
That was always my goal with Pure Blog - a super simple, distraction-free blogging platform out of the box, with enough flexibility under the hood for tinkerers (like me!) to build whatever they want.
If you're running Pure Blog and have built your own customisations, or if this post inspired you to try something new with your setup, hit the reply button below, or find me on Mastodon. I'd love to see what you've done with it.
Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️
You can reply to this post by email, or leave a comment.
2026-10-31 21:58:00
This is a follow up to my post where Widdershins talks about how they agree with certain parts of my argument, but that the discoverability piece is flawed.
Saw this in my RSS feed and thought it was an interesting take that's worth sharing - also Widdershins' blog is excellent. I'd recommend adding it to your feed reader.
I think the argument around other people controlling the gate to discoverability is a sound one, generally, but sites like Bubbles tend to add most sites, unless they're somehow obnoxious. So inclusion (and therefore discoverability) is only an email away. Having said that, one person's obnoxious is another person's heaven, so it's all subjective.
Either way, it's an interesting debate and I'm glad we're having it. Go check out Widdershins' blog too!
Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️
You can reply to this post by email, or leave a comment.
2026-10-31 00:36:00
I've seen a few people talking about SocialSpec which claims that "the future of social media is websites". Something I strongly agree with. However, I don't see the point of this fledgling spec on top of all the other IndieWeb complexity that's flying around.
From what I can gather, it's 3 files that you upload to /.well-known which provide a bio, a means of contact, and what blogs you follow. Step one is to have an RSS feed, actually, but everyone should have an RSS feed anyway. But aside from this, I already have a bio, a means of contact, and a list of blogs I follow. So what is SocialSpec trying to achieve?
Again, from what I can gather from the site, you publish these 3 files on your site and you're magically enrolled in the new website social network. Where you can peruse a timeline of posts from fellow bloggers, based on who you follow in your OPML file.
Fuck yeah! Win for the open web. Sign me up!
But hang on a second. This open spec, based on open protocols, for the open web doesn't even have a web app. Nope. The only client that actually uses it is sitting behind a fucking iOS app.
Now I'm sure other apps will come with time, but if this were truly a platform for the open web, wouldn't a website that supports a PWA have been a better solution initially? I think so.
Even if someone takes the time to publish and maintain these files, what does SocialSpec offer over an RSS feed reader, and a couple of pages on your site?
Nothing.
I like how people are thinking of ways to interconnect sites in this way, but I don't think this is the right approach. It's trying to solve a problem that doesn't really exist in my opinion. The only issue it may fix is discoverability. But I still think it's flawed as the service would need a decent user base to make discoverability viable.
Sites like Bubbles, PowRSS, and Bear Discover are far better than this solution as they're easier to use and have no barrier for entry.
Maybe I'm being a curmudgeon here, but I really don't get it. This is a solved problem, and has been for decades.
Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️
You can reply to this post by email, or leave a comment.
2026-10-29 22:56:00
Been having some fun with my 404 page. I love discovering little Easter eggs like this on other people's sites. Just visit a random page, like https://kevquirk.com/mjkk
Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️
You can reply to this post by email, or leave a comment.
2026-10-28 03:43:00
Author: Matt Dinniman
Genre: Sci-fi
Released: 2021
Rating:
New Achievement! Total, Utter Failure. You failed a quest less than five minutes after you received it. Now that’s talent.
Surviving in a multilevel dungeon that also happens to be the set of the galaxy’s most watched game show has taught Coast Guard vet Carl and his ex-girlfriend’s cat, Princess Donut, that there’s only one thing they can count on apart from each they never know what’s coming next. And this floor is no exception.
A floating fortress occupied by warrior gnomes. A castle made of sand. A derelict submarine guarded by malfunctioning machines. A haunted crypt surrounded by lethal traps.
It was supposed to be easy. One bubble. Four castles. Fifteen days. Capture each one, and the stairwell is unlocked. Here's the thing. It's never easy. Going it alone is not an option this time, so Carl and his team must rely on the help of the low-level, I-can't-believe-these-idiots-are-still-alive crawlers trapped in the bubble with them. But can they be trusted?
Welcome, Crawlers. Welcome to the fifth floor of the dungeon.
Dungeon Crawler Carl is a fun series of book, but like number 3 this one felt like a bit of a drag up until the last 1/5 of the book, where I think it got better. I particularly like how Carl is starting to really establish himself in the dungeon now and continues to put two fingers up to the powers that be.
I felt that the story arc was really slow to get going on this book, but once it did gain momentum, it was enjoyable.
I've been reading these books back to back; there's other books I want to read, so I think I'm going to take a break from reading these books and will switch to something else.
I won't stop consuming the series though - my backlog of podcasts has dwindled lately, and lots of people have recommended the Dungeon Crawler Carl audiobooks. So I've started listening to book #5 in the car and on walks, and will switch to reading something else.
Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️
You can reply to this post by email, or leave a comment.
2026-10-25 02:47:00
Hooman. I believe it is dinner time.

Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️
You can reply to this post by email, or leave a comment.