Kirby in a nutshell
Or what you wish you had known when you started your first Kirby project.
Everyone has their own way of going about things. What works for you, might not work for others. And the things to consider vary for each project, depending on whether you are migrating from another system or whether you are trying to set things up from scratch, whether your project is small or really huge, and so on.
So this recipe is not so much about best practices, it is rather intended to give you an idea of how Kirby works, what you might want to keep in mind when you start your project with Kirby, what questions you might want to ask yourself and about possible approaches, no matter if you are completely new to web development, or if you come from other systems.
Not all aspects mentioned here will apply to your particular project, so just skip the parts that don't. While it might be a little bit confusing at the beginning that there are different ways to go about things, that is really what makes Kirby special: Rather than forcing a special workflow on you, it lets you create things the way that fits your mental model.
Kirby is all about giving you the freedom and the tools to create what you want, the way you want–for yourself or your clients. The philosophy is to keep things as simple as possible and to add only what is needed. You can start with a very basic setup and then extend later when new requirements come up.
However, this freedom to create also means that you basically start from scratch and then build your project step by step, a bit like building with Lego™ blocks. It means that you need to know the basics like HTML and CSS, and some PHP (or be prepared to learn what you need along the way). While quite a few themes for Kirby are available to get you jump-started on getkirby-themes.com, you will have to touch code to make changes if these themes are not a 100% fit. The idea behind Kirby is to empower you to create your own unique site and not make your project look like thousands of others out there.
Kirby is a flat-file CMS. That means, your content lives in files and folders, not in a database.
Inside those folders, there are text files with a file name and an extension (
.md), for example,
projects.txt. These file names can be different for each page, or multiple pages of the same type (like articles, projects etc.) can have the same text file name. Each content file name therefore represents a page type. Each page type can have its own page model.
Example content folder structure:
Page blueprints for this structure:
Next to the content folder, there is a second important folder in your installation: the
/site folder. It contains templates, blueprints, plugins, user accounts, models, controllers etc.
These file names are important, because the whole Kirby system is based on matching file names. There is usually also a strong tie between content and templates.
If you create a page with a given content file name, this page will be rendered in the frontend with a PHP template of the same name and the extension
.php. If such a template does not exists, the
default.php template will be used.
In the same way, if you create a new page in the Panel with a blueprint called
whatever.yml, the resulting content file name will be
whatever.txt. Here are some examples:
|Defines the form fields for the Panel||Contains the content||Renders the content on frontend||Contains the logic if required||Extends the default page object|
Some people always start with a basic content folder structure. Others start with creating all the blueprints for the Panel. Yet others create one page after the other. It doesn't really matter where you start, and you should absolutely do what works best for you and makes you happy, but having a basic idea of your final structure helps a lot.
Here are some questions you might want to ask yourself:
- What are the main pages?
- Which pages are basically only containers for subpages but do not have any content of their own (for example a blog page that shows a list of articles where the articles themselves are subpages)? Should these subpages be accessible via their own URL or only shown on the parent page?
- Which pages are containers for content that comes from other pages (for example a home page with different sections made from different parts of the site)?
- Is a flat structure with a couple of main pages sufficient? Or is it a more complex site that requires a deeply nested tree structure?
- Which page types need what sort of content? Some pages maybe only have a textarea field for long text, others might be a lot more structured with different types of content fields.
- Which page types should share the same structure–and hence the same blueprint?
- Are there any fields/tabs/sections that are always the same or appear in multiple areas, so that you can create blueprint "partials" for reuse?
- What sort of global content do you need and where to store it? (spoiler: in
- Is the site going to be translated into multiple languages? What should be the default language?
The beauty is that all these different structures can be built with Kirby and there is hardly any limitation. You might not be able to answer all these question right from the beginning, but they can guide you when building the different parts of your site.
Folder names (the so-called "slugs") are important as well. Folder names will become part of the URL of a page.
|Folder name||Resulting URL|
Therefore, if you change the name of the folder (directly in the file system, through the Panel or programmatically), you also change the URL of the page. This doesn't matter so much during development, but it has some implications to be aware of and to keep in mind.
Field names can sometimes lead to confusion. Ok, field names may only contain alpha-numeric characters and underscores, that's one thing. But field names can also collide with native Kirby methods. Let's assume you set up a
files field like this in a blueprint:
fields: image: type: files max: 1 query: page.images
If you try to call this field in your template like this…
<?= $page->image()->toFile() ?>
…you will probably be very surprised to get no result at all. That is because the
image() method is a native Kirby method that will fetch the first image it finds in the file system. And since a file object doesn't have a
toFile() method, the above code will not echo anything, unless your file meta data has a field with that name. Since there a quite a few native Kirby methods and plugins might add even more, it is easy to accidentally pick such a method as your field name.
You can do one of two things to solve this:
- Call such fields via the
- Prevent such issues by prefixing all your field names:
Different field types store their content in different ways. While a
text field stores a string, a
multiselect field stores a comma separated list of values, the
pages/files fields or a
structure field store their content in YAML format, and the editor field stores its content in JSON format. Kirby comes with useful field methods which convert these different values into something usable in your templates.
This is no problem if field types are the same. However, if you decide to make changes to field types in a blueprint during development, or you allow changing templates, you have to be a bit careful.
Pages and files can be organized in the Panel using files/pages fields or files/pages sections. It is important to understand the difference between these two types to make informed decisions when to use what.
- Shows a list of existing pages with an option to create new pages.
- Pages in a pages section can only have a single parent page which is defined with the
- Pages are filterable by their template + status only.
- A pages section doesn't store anything in the content file.
- Is basically a select field that allows selecting pages from a given set of pages.
- The selectable pages can be from different parents, the set is defined via the
queryoption. If no query is defined, the field options default to the children of the current page.
- The ID(s) of the selected page(s) are stored in the content file.
- Currently there is no option to create new pages from a pages field.
- A typical use case is creating references between pages, for example to manually select related pages.
- Upload one or more files at once to a single parent
- Files can only be uploaded to a single page. The destination is set with the
- Files can be filtered by template only
- You can limit what type of files can be uploaded with the
acceptoption in the given files template
- Files are uploaded to the given parent
- The IDs of the uploaded files are not stored anywhere
- Select one or more files from a (larger) set of files
- The ID(s) of the selected file(s) are stored in the page’s content file
- Upload a single file at a time, the newly uploaded file is then automatically selected
- Deleting a file uploaded via the files field is only possible via the file view (or through a files section), not directly from the files field
- Templates can be assigned to uploaded files via the upload option
- The files to select from can be defined using the
queryallows you to fetch files from different parents and to filter the set by any criteria. If no query is set, the field defaults to files of the current page
- You can only upload to a single page. The default parent is the current page
The Panel dashboard is the first page users get to see when they access the Panel. In its most basic form, it provides a kind of sitemap to all or the most important pages of the site and can also contain fields for global information like a top level SEO title and description, the company name and address etc., that is, information that is not tied to a particular page.
The form fields and sections for the dashboard are defined in the
/site/blueprints/site.yml blueprint. The text file for the
$site object is called
site.txt and lives directly in the content folder. Next to the
site.txt file you can store media files that belong to the
One-pager websites or generally pages that contain different sections (often with repeating types of content) can be realized in multiple ways:
- The sections are created as subpages of the parent page, like in our one-pager example.
- The sections are created using Tim Oetting's Builder plugin.
Here are some guidelines that help you pick the right solution for your project:
- Subpages can be as complex as needed and can themselves contain structure fields or subpages if needed.
- Subpages are probably easier to handle if the sections contain a lot of content.
- Subpages are by default accessible via their URL.
- Without a plugin that allows you to skip the title, every subpage needs a title.
Options to circumvent some disadvantages:
- Store sections in their own sections subfolder.
- Create page models to rewrite the URLs.
- Use routes to prevent access to the section URLs.
- Use the Custom Add Fields plugin that allows skipping the title when creating new section pages.
- All content is created in the same page.
- Nested structures are possible but should probably be limited to two levels. Nested content cannot be moved between blocks.
- Easy creation of new blocks.
- Better preview of final result.
- No redirecting necessary.
- Currently not compatible with the Editor plugin
Whenever you upload a file to a page via the Panel, the file is uploaded to the content folder. However, as soon as the URL of the file is called in the browser, the file is copied to the media folder. Also, all thumbnails are created on the fly and stored in the media folder. Therefore, this folder needs to be publicly accessible within the document root. This setup was chosen because it has some real advantages, like providing consistent image URLs or being able to move the content folder (and most other folders) above the document root for better security (see custom folder setup).
Kirby natively supports translating content into multiple languages. From the file-system perspective, the multi-language feature is implemented by adding a language code to the text file name, for example,
projects.en.txt etc. These language files all live in the same content folder.
Once you create your first language, the content text files must have the language extension, otherwise Kirby doesn't work as expected. The extension is added automatically if you create your languages via the Panel. If you create new languages manually, you have to add the language code extensions manually as well.
Some things to keep in mind when dealing with languages:
- The content file for the default language is always created through the Panel, no matter which language is currently active when you add a new page.
- In the frontend, Kirby falls back to showing the default language content if a page doesn't exist in the target language. You can prevent this by filtering your content by language.
The file system is really powerful and fast, and creating web projects with thousands or tens of thousands of pages is not usually a problem. However, thousands of pages shouldn't all reside in the same parent but rather be distributed in a tree-like structure. There is no hard limit as to how many pages should be in a single parent as this also depends on the performance of the server and the number and size of media files.
Beyond a certain size, try to avoid calling the
$site->index() method because it reads the entire folder structure including all files which can result in big performance issues.
Also, use caching wherever possible to improve performance.
At its heart, Kirby is file-based CMS, we already said that somewhere at the beginning of this long winding article, right? But Kirby wouldn't be Kirby if that was the limit. Where file-based storage is too limiting, you can add a database. If you want to integrate content from other sources like an API, a feed, a spreadsheet: go ahead.
All virtual pages are seamlessly integrated in Kirby. Routing works out of the box, they are included in API requests and they are even manageable in the Panel!
Get started! Any questions? Visit our forum and ask us anything.