Notes on Kirby CMS
Some initial notes, as I learn my way around Kirby CMS.
Development flow
See: Development flow.
Security
A secure Kirby deploy must prevent HTTP access to some of its files and folders, as outlined in the Security guide.
Both distributions (Plainkit and Starterkit) come wih an .htaccess file which enforces these rules for Apache and compatible servers. There is also a recipe for running Running Kirby on a Nginx web server.
Content modeling
See: Content modeling in Kirby.
Templating
Kirby uses plain PHP as the templating language but provides a neat, object-oriented API that makes templates easy enough to read.
Templating is pretty lean: a content file named project.txt will use the /site/templates/project.php template file, if it exists. Other than defaulting to /site/templates/default.php, there’s no other prescribed template hierarchy as with WordPress.
The mechanism for template reuse is snippets with slots, which is enough to stand in for Twig’s extend and include tags. Speaking of which: Twig is available as a separate plugin, along with other templating languages, should you find plain PHP unpalatable.
To prevent XSS vulnerabilities, values in templates can be escaped with:
- the
esc()global helper in templates $field->esc()for fields specificallyStr::esc()in other PHP code
These methods accept a $context which lets you target different escaping contexts.
Developing custom interfaces
Custom interfaces for the Panel are defined in Plugins, which tend to have two parts:
- the plugin’s
index.phpfile for back-end stuff - the plugin’s
index.jsfile for front-end stuff, preferably written as Vue components like the rest of the Panel
The front-end generally interacts with the back-end via the Kirby (REST) API.
A custom Panel section
In addition to working with the REST API, you can fetch data for a custom Panel section in the plugin’s index.php file with computed properties.
This allows the user to configure the panel section when using it in a blueprint.
For example, you could have a query property in the section that gets interpreted as a query string, just like some built-in fields work, which you can use to drill down into arrays/objects with Kirby\Toolkit\Str’s query method:
use Throwable;
try {
return Str::query($query, [
// data
]);
} catch(Throwable) {
return null;
}
Note: the
try/catchblock is necessary because anynullwithin the chain will cause the query to throw. [TODO: is that really the case?]
In a custom panel section, $this refers to the section and $this->model() refers to the object associated with the page, eg. on a user page it returns the associated user.
Dates, times, and timezones
For a quick overview of the various date & time formats, see A Venn diagram of date and time formats, according to RFC 3339 vs. ISO 8601 vs. HTML.
Kirby’s Date and Time fields don’t store the timezone information in content files. A typical date-time string looks like this, which corresponds to the "Y-m-d H:i:s" PHP format string.
Start-date: 2023-08-28 09:00:00
When used in PHP date objects, the server timezone is assumed by default. We can declare an explicit timezone as the first thing in Kirby’s index.php file:
date_default_timezone_set('Europe/Bucharest');
To send dates to the client, including the timezone we’ve set up, to be parsed as JavaScript date objects we use the DateTimeInterface::W3C format, an alias for "Y-m-d\\TH:i:sP".
new DateTimeImmutable($date_string)->format(DateTimeInterface::W3C);
In the opposite direction, we want to accept dates from the client in the format produced by date.toISOString(), which is always in explicit UTC, denoted by the suffix Z. A typical date-time string looks like this:
{
"start_date": "2023-09-16T16:26:38.428Z"
}
When Kirby prepares a date-time string for storage, the timezone seems to be ignored, resulting in the incorrect date to be stored. To work around this, we need to convert from UTC to the server timezone, then format it as Kirby would when it saves the date to the content file.
function toKirbyDate($date_string) {
return (new DateTimeImmutable($date_string))
->setTimezone(new DateTimeZone(date_default_timezone_get()))
->format("Y-m-d H:i:s");
}
Images
See: Images.
Limitations
When requesting an image size larger than the original, the srcset() function will assume the image was upscaled, when it’s not (see [kirby#2071]).
You probably want locale-aware sorting
By default Kirby ignores locale rules when sorting things. In Romanian, this manifests in letters with diacritical marks (Ă, Î, etc.) being shifted to the end of the alphabet.
A Pages section’s sortBy property accepts the SORT_LOCALE_STRING keyword to enable locale-aware sorting, and so does the $pages->sortBy() method.
Users and permissions
Quirks and workarounds
Filling in Panel fields with JavaScript
In a page edit screen, I needed to fill in a whole set of fields with JavaScript. Kirby uses Vue 2.7 for the Panel front-end, and it would not pick up correctly on the external DOM updates.
Without looking too much into it, a workaround is to emit an input event and pause for 100ms before moving to the next field.
Instead of:
function populateFields() {
const FIELD_NAMES = ['headline', 'excerpt', 'description'];
for (const name of FIELD_NAMES) {
const input = document.querySelector(`[name=${name}]`);
inputEl.value = 'some-value';
};
}
You can do this:
async function populateFields() {
const FIELD_NAMES = ['headline', 'excerpt', 'description'];
for await (const name of FIELD_NAMES) {
const input = document.querySelector(`[name=${name}]`);
inputEl.value = 'some-value';
inputEl.dispatchEvent(new Event('input'));
await new Promise(r => setTimeout(r, 100));
};
}
Languages and translation
See: Languages and translation.
Providing contextual help
See: Contextual help.
Sitemaps and meta tags
See Tobias Möritz’s Kirby SEO plugin for a ready-made solution.
Miscellaneous
Maintenance mode. Add a boolean option to the site blueprint to toggle maintenance mode on and off, then in the base template:
<?php
if($site->maintenance()->toBool()) {
snippet('maintenance');
exit();
}
?>
Further reading
- Kirby’s documentation is quite good!
- Kirby support forum may have solutions for questions not answered in the official docs.
- Kirby School is a video course by Kristian Maňas.
- Moinframe by Justus Kraft.
- Kirbysites showcases how the Kirby Panel is organized in various websites (see everything at once with the power user mode).
Starter kits
tobimori/kirby-baukasten, abatteries-included Kirby 5 Boilerplate with Tailwind CSS, Alpine.js, TypeScript, Vite & other best practices
;femundfilou/kirby-blaupauseby Justus Kraft,a starter for new projects, mainly developed out of personal needs. It’s based on the tools and technologies we work with and might serve as an inspiration to others
.1612elphi/kirby-grimoire,a web publishing tool / theme for Kirby, batteries included
.tocmai/tocmaikit, a minimal starter by yours truly.