Migrating from Eleventy to Kirby
I wrote a post a while back toying with the idea of migrating my personal site from Eleventy to a new platform with more built-in content management features. Over my recent holiday break, I decided to give Kirby a go and was able to migrate and launch my new site after a few weeks of work. I've seen other folks online posting about potentially migrating to Kirby, so I thought I'd take some time to write up my experience migrating and launching a new Kirby-powered site.
This isn't meant to be a tutorial on how to use Kirby. The Kirby docs are very thorough, well-written, and some of the best out there, in my opinion. If you want to learn how to build a Kirby site, I would start there. My goal here is to share my experience of migrating my site and why I chose to move away from a static site generator. If that sounds interesting or helpful to you, keep on reading!
About Kirby
At it's simplest, Kirby is a file-based CMS that allows you to write content in text files. Content is stored as plain text in .txt files. Kirby reads content files from disk and displays a page when a user visits a URL on your site. There is no database involved by default, but it is possible to integrate external data sources. It's written in PHP and includes, among lots of other great features, the following:
- A robust templating system
- An optional, but very flexible admin UI (the Panel) for managing content.
- A powerful plugin system with lots of good community-contributed plugins
- Easy and flexible image processing
- Excellent documentation, a helpful support forum, and an active Discord community
Kirby can be easily hosted on most shared hosting providers and in my experience, can make very fast and performant websites. I've got an old shared hosting account that I started using again for my new site and there hasn't been any noticeable dip in performance and/or page load. That's after migrating from a fully static site hosted on Netlify's super fast edge CDNs.
Managing content
All content is stored as plain text files in folders which makes Kirby very fast and reliable. If you want to keep things as simple as possible you can write all of your content in Markdown (or KirbyText) inside of plain .txt files and then just upload those to your server. In addition to Markdown you can write structured data in a front matter-like YAML syntax that Kirby calls fields. You then have access to your content and structured data in your templates. Coming from Eleventy, this set up feels very comfortable to me. A typical Kirby content file might looks something like this. Each field is a key/value pair written in YAML.
Title: My first post
---
Date: 2023-03-01
---
Cover: my-cover-image.png
---
Write normal **markdown** content here...
In Kirby you keep any related media like images in the same folder as your content .txt files so referencing images like in the previous example is as easy as providing the file name. This co-location of assets with content files also works for CSS and JavaScript files too—hello, easy art directed posts!
The Panel
Kirby also comes with a content management UI called the Panel, which is available in a default Kirby install at yoursite.com/panel
. The Panel allows you to easily configure an admin UI that is tailored to your content using YAML files called Blueprints. In Blueprints you configure the fields you want to use and the layout of the admin interface. It's a very straightforward and powerful system for creating structured content. Under the hood the Panel is just writing input from fields in your Panel to the same .txt files that you can also edit by hand.
I've only scratched the surface when it comes to what you can do with the panel, but the previous image shows what my Panel looks like for blog posts.
Migrating content
I was planning a total redesign toward the end of last year which meant by the time I got started on the migration to Kirby I had already built out the HTML and CSS for the majority of my site. I was starting from a blank slate, so the only real migration that need to be done was the content. My site was previously built in Eleventy, so all the content was already in Markdown which Kirby supports out of the box. I considered the idea of writing some sort of script to migrate all of my existing Markdown files to Kirby's similar, but slightly different .txt
file format, but decided instead to move content over manually and take the opportunity to clean up, edit, and cull some of the Markdown in my old posts.
While setting up the main Blueprints for my new Kirby installation, I decided to use the Blocks field for the main content of each page/post on my site. The Blocks field is "A visual editor for long-form text and modular pages" as it's described in the Kirby docs. It's similar in concept to the WordPress block editor and allows you to use various pre-defined content blocks that you can drag and drop to reorder. When you use the blocks field, the content is stored in a big JSON array of block objects. For example, the Markdown block stores content in an JSON object that looks something like the following.
{
"content": {
"text": "This JSON field contains the [Markdown]([...](https://www.markdownguide.org/getting-started/)) for a block of text."
},
"id": "bb91e03c-7393-4087-aa22-b20d1d84ac74",
"isHidden": false,
"type": "markdown"
}
Migrating would have been easier an more automate-able if I had used the regular text field (which supports Markdown) for the main content of pages and posts, but the Blocks field seemed like a really appealing way to write and edit posts, so the manual migration process was a bit tedious. The good news was my blog was only about 45 posts at the time of migration, so it took me less than three hours to migrate all the content to Kirby blocks.
Templating
Templates in Kirby are .php files that contain the HTML for your pages. You use PHP inside of templates to dynamically render content. When I think of PHP templating my mind immediately goes to WordPress' rats nest of a templating system (or lack there of), but Kirby does PHP templating pretty well, in my opinion.
To create a new template for a content type you add a new .php file to your /site/tempaltes/
folder with the same name as your .txt
files for that content type. For example, if you call have a content type named "post" with a folder structure like this: /posts/my-new-post/post.txt
in your content folder then all you need to do is create a templated at /site/templates/post.php
and all posts will be rendered with that template. Pretty cool!
Data in templates
Inside your templates you have access to $page
, $site
, and $pages
variables by default which allow you to access the content/fields of your pages and site. For example, if you have a field in your about page content file called description
, I can access it in my templates like this <?= $page->description() ?>
. This is very similar to Eleventy and other static site generators. There are several other ways to get data into your templates like controllers, and collections, but those concepts are beyond the scope of this post.
Given a content file that looks likes this:
Title: My post
---
Description: A cool new post about Kirby!
---
Date: 2023-03-03
You can access these values in your template like this:
<h1><?= $page->title() ?>
<p><?= $page->description() ?>
<time datetime="<?= $page->date() ?>">
<?= $page->date()->toDate("M j, Y") ?>
</time>
Kirby also comes with a lot of template helpers right out of the box that make it easy to do things like sorting, date conversion (see previous example), and lots of other super helpful stuff. I won't go into all of those helpers here, but there is a really great primer on templating in Kirby on the docs site.
Snippets and slots
Snippets are the way Kirby handles including re-usable pieces of code across multiple templates. Until recently they worked mostly similar to languages like Nunjucks includes and macros where you could use them to just include a piece of code or pass variables to them which made it possible to render different types of data based on context.
Earlier this year the Kirby team release an update to snippets that added a new slots feature, which kind of rules. If you've used Web Components and/or frontend libraries like Vue, then slots will feel very familiar. This feature allows you to create slots inside of snippets where you can render content from the parent template where they are used. This opens up a lot of cool possibilities to build self-contained component-like snippets or even use them for template inheritance.
Here is what my base template that wraps every other template on my site looks like. That <?= $slot ?>
is the default slot in the snippet where everything gets rendered.
<?= /* /site/snippets/layouts/default.php */?>
<!DOCTYPE html>
<html lang="en">
<head>
<?= snippet('head-content') ?>
<?= css('assets/css/styles.css') ?>
</head>
<body>
<?= snippet('header') ?>
<main id="main-content">
<?= $slot ?>
</main>
<?= snippet('footer') ?>
</body>
</html>
And here is what that layout snippet looks like in-use with my post template. The markup is simplified for demo purposes.
<?= /* /site/templates/post.php */?>
<?php snippet('layouts/default', slots: true) ?>
<?php slot() ?>
<h1><?= $page->title() ?></h1>
<?= $page->text()->toBlocks() ?>
<?php endslot() ?>
<?php endsnippet() ?>
Pretty cool. I've not had a ton of time to dig into snippets with slots yet, but I'm planning to refactor the templates on my site later this year to make better use of this great new feature.
Pros and Cons
So far I'm very pumped about my new site. I'm really enjoying using the Kirby Panel for writing and editing new posts. The block editor is a lot of fun! I didn't realize how many features of a more traditional CMS I missed having. One of my goals in migrating to Kirby was to eliminate as much friction as possible when writing and posting on my site. Kirby makes editing and posting new content a breeze. I can even write and updated content from my phone using the Panel, which is super valuable for someone like me that generally has at least a few typos in every new post.
Code updates and deployment
Hosting my old site on Netlify also made deploying design and functionality updates a bit easier because of the tight integration with GitHub. Updates were just a matter of pushing from my local Git repo and then seeing the changes go live almost immediately. While it's possible to use services like DeployHQ with Kirby to do the same thing, I've opted to stick with a pretty straightforward rsync deployment script (based on this article) that is working out just fine for now. It's a touch more sophisticated than a FTP drag-and-drop situation, but to be honest, I'm also kind of ok with FTP these days too.
Long-term portability
While the blocks field is a lot of fun to use and a really powerful way to edit content, I do think about the long-term portability of the content on my site. Markdown is ubiquitous on the web and probably will not be going away any time soon. I'm using the Markdown block in Kirby so my content is still technically being stored as Markdown, but it is inside of a JSON array which makes it a more difficult to port to another CMS or static site generator should I ever want to migrate of of Kirby. I'm not too worried about this since it would be very possible to write a script that would convert the JSON array of Kirby blocks back to regular Markdown files.
Wrapping up
For anyone thinking about making the move to a CMS from a static site generator, I would highly recommend checking out Kirby. On top of all the great features it offers out of the box, it has a vibrant and helpful user community and the project is very active and well-managed with lots valuable and thoughtful features released on a consistent basis. In a time where personal sites seem to be making a comeback, I'm very happy to have mine running on Kirby.