🚀 A new era: Kirby 4 Get to know
Skip to content


The data structure behind a Kirby site is very simple: one folder = one page. But this does not mean that you have to stick to this pattern. In fact it’s very simple to build a one-page website with multiple different sections and still have a folder for each section.

One-page websites are very popular for small businesses, freelance designers, photographers, etc. It’s the modern version of a printed business card and can be very effective to represent a small business without the hassle of maintaining a huge site.

In this tutorial we are going to build a very basic one-pager. Here’s a rough mock-up to show you what’s coming up:

The content file structure

  • 1_about-me
    • about-me.txt
  • 2_projects
    • 1_project-a
      • project.txt
    • 2_project-b
      • project.txt
    • 3_project-c
      • project.txt
    • 4_project-d
      • project.txt
    • projects.txt
  • 3_testimonials
    • 1_testimonial-1
      • testimonial.txt
    • 2_testimonial-2
      • testimonial.txt
    • 3_testimonial-3
      • testimonial.txt
    • testimonials.txt
  • 4_contact
    • contact.txt
  • error
    • error.txt
  • home
    • home.txt

This looks like a regular Kirby-powered website with multiple subpages, but this will work just great for our single-page website as well.

Why listed folders?

We have a listed folder (those with the prepended numbers) for each content section on our site. Marking them as visible will help to fetch them in the next steps and prepending the numbers also gives us the option to sort the content sections. So if you feel like the testimonials section is more important than your projects later, it’s just a matter of changing those numbers to resort the sections.

Home and Error Pages

There’s an additional invisible home folder with a home.txt. This is needed to tell Kirby that the homepage has a home.php template, which will be used to display all the sections above. We’ll get to that later.

The error folder is used to display a 404 error page, when someone tries to access a non-available page on your site.

Projects and Testimonials

As you can see, there’s an additional level of subfolders for projects and testimonials. Each project and testimonial folder will give us the option to store data for them separately and even attach images or all other kinds of files. You will still be able to list projects and testimonials on your site, even if there's not a dedicated subpage for each project or testimonial. We’ll get to that later as well.

The data

You are free to add whatever fields you need in each text file. Here are some possible setups for all the different text files:

title: About me
text: Some text about you and your skills
title: Projects
text: An introduction to your work
title: Project title
text: Project description
year: maybe a year when the project has been created
tags: maybe, some additional, tags, to characterize, the project
url: http://projecturl.com
title: Testimonials
text: an optional introduction text for the testimonials section
title: John Doe
quote: This dude is the best photographer in the world
url: http://yourtestimonialswebsite.com
title: Contact
address: 123 Sesamestreet, NYC
email: mail@mywebsite.com
phone: 555 - 1234 5678

The home.php template

Since the data structure is now ready, we are going to create our first and most important template. Go to /site/templates and create a new home.php template file.

This will be our main template for that one page we got. The HTML for that template is very basic:

<?php snippet('header') ?>
<?php foreach ($pages->listed() as $section): ?>

<!-- html for each content section -->

<?php endforeach ?>
<?php snippet('footer') ?>

In your header.php snippet you are free to add the logo and all other elements you need for the top part of your one-pager. The same applies to the footer.php snippet.

In that simple foreach loop in the middle, we are fetching all those visible subpages:

  • 1_about-me
  • 2_projects
  • 3_testimonials
  • 4_contact

You could now just create HTML for each section, but since not all sections require the same HTML structure, we somehow need to separate this. The best way to do that is to use individual snippets for each content section.

The uid() method

Kirby has a very handy built-in method for each page, which returns the name of the content folder without the prepended number. You can call it like this:


We can make use of that for naming and including snippets for each content section:

<?php snippet('header') ?>
<?php foreach($pages->listed() as $section): ?>
<?php snippet($section->uid()) ?>
<?php endforeach ?>
<?php snippet('footer') ?>

This piece of code will try to include an accordingly named snippet for each section:

1_about-me     -> /site/snippets/about-me.php
2_projects     -> /site/snippets/projects.php
3_testimonials -> /site/snippets/testimonials.php
4_contact      -> /site/snippets/contact.php

All you need to do is to create a snippet for each section now and you are able to create individual HTML for all of them.

Since there are a lot of unnecessary PHP tags in our home template now, we should clean that up a bit:



foreach($pages->listed() as $section) {
  snippet($section->uid(), ['data' => $section]);



You can also see that we added a little detail in the middle, when loading those specific snippets:

snippet($section->uid(), ['data' => $section]);

What we’re doing here, is to pass the data for each $section to each snippet. This will make it possible to access all the content variables, which are stored in the text files.

You can read more about how to pass variables to snippets in the docs.

The section snippets

If you try to open the homepage of your site now, you will find the header and the footer and nothing in between. Kirby will try to find all those snippets in the middle, but since you’ve not created them yet, it will just render nothing.

This is quite handy, because now you can take your time for each of the content section snippets and create them step by step and each section will appear as soon as the snippet is available. It’s almost like playing puzzle.

Accessing the data

Let’s create the about-me.php snippet together to show you how to access the data from the text files in each section snippet:

<section id="about-me">
  <h1><?= $data->title() ?></h1>
  <?= $data->text()->kirbytext() ?>

The about-me.php is probably going to be the most basic snippet, since it will only have a headline and some text. Remember that we defined a title and a text field for that in the about-me.txt. Since we passed the data for each section to each snippet with ['data' => $section] we now have access to all the custom content fields with the $data variable.

This is true no matter how many fields you define in your text files. Together with the different snippets for each section this is a very powerful toolset to create whatever you need for your one-pager.

Let’s get a bit more complicated

The about-me section was pretty straightforward, but something like the project section is going to be way more complex. If you take a look at the file structure above, you will find that we added another subfolder for each project. I’m now going to show you how to create a nice project section with all those added projects.

<section id="projects">
  <h1><?= $data->title() ?></h1>
  <?= $data->text()->kirbytext() ?>

    <?php foreach($data->children()->listed() as $project): ?>
          <img src="<?= $project->image()->url() ?>" alt="<?= $project->title() ?>">
    <?php endforeach ?>

As you can see, you can access those project subfolders by using $data->children()->listed(), which gives you a $project variable for each project, including all the data you've entered for your projects. And you can even access images in your projects folders that way.

In this example we’ve only created a simple list of projects with images, but of course you are free to extend this way more and include all that metadata, like tags or the year or whatever you need.

You can use the same principle for testimonials. In fact we’re doing something very similar for testimonials on the Kirby homepage. I’ve combined that with the limit() and shuffle() methods to show a random list of three testimonials on the homepage, while there are lots of other testimonials stored in more subfolders.

The default.php template

We still got the default.php template in our template folder and that’s good. The default.php template will be used by Kirby whenever there’s no matching template for a text file. For example if we go to http://yourdomain.com/projects now, Kirby will try to render a projects page with a projects.php template, since the text file for that page is called projects.txt. But we don’t have a projects.php template and thus Kirby will fall back to the default.php and use that instead.

Since we don’t want any subpages at all, we don’t want Kirby to display the projects page at all. We also don’t want any other pages to be displayed, except the home and the error page. This is where the default.php template comes in handy.

Templates don’t have to necessarily contain HTML. You can redirect to other pages for example or you can display nothing or any kind of code you want. In this case we are going to make use of a redirect.

<?php go() ?>

If we add this to our default.php all the pages, which use that template will automatically redirect to the homepage. If you are crazy, you can use that to redirect to Google or a site full of kittens or whatever you prefer:

<?php go('http://google.com') ?>

But maybe it’s better you redirect to the homepage instead :).

Another option would be to redirect to the error page, so you make clear that this page is not available.

<?php go('error') ?>

The error.php template

As a final step you should setup a proper error.php template. It doesn’t have to be something super fancy, but it will make your entire site a bit more polished.

Final thoughts

With those steps, you get a very comfortable setup for your “one-pager” which you can update and maintain. But please just take this as an inspiration for your own project. It’s up to you to stick those pieces together in a way you are most happy with. Working with subfolders not only for full rendered pages can be a very cool way to store and retrieve data with Kirby. Once you get the hang of it, you will be able to come up with pretty much anything you have in mind.