Skip to content
Kirby 5 is here! Learn more

Content from a database

Load data from database and show it as pages

Content can also come from a database. This is particularly useful if you already have a large set of data stored in a MySQL or other relational database, like a database of products or articles. You can transform data from such databases into Kirby pages that behave like any Kirby page in the frontend, i.e. you can use Kirby’s API to access, filter, or search the content.

This guide covers the basic steps, such as establishing a connection to the database, accessing one or more tables, and converting database entries into children of a parent page in read-only mode. In this setup, the pages are generated dynamically from the database and cannot be modified through the Panel or written to the file system.

To add advanced functionality (editing, adding, deleting pages, etc.), please refer to our our database storage plugin (currently in alpha).

Our example assumes a database table called comments with the following schema:

Column Datatype Primary Key Unique
id INTEGER yes yes
title TEXT no no
slug TEXT no yes
text TEXT no no
email TEXT no no

You can, of course, work with an existing table if you adapt this guide accordingly.

Create a new parent page

Now create a new parent page called comments in the content folder and add a comments.txt file inside it. The file system should look like this:

  • content
    • comments
      • comments.txt

This file will connect the page with the `comments.php template and – more importantly – a new CommentsPage model we will create in the next steps.

Create a template and page model

Create the following files:

  • /site/templates/comments.php
  • /site/models/comments.php.

Connect to the database

In your config.php, connect to the database:

<?php

return [
    'db' => [
        'host'     => '127.0.0.1',
        'database' => 'kirby',
        'user'     => 'root',
        'password' => 'root',
    ]
];

Here we connect to a local database, your real database should, of course, use a proper database user and secure password.

Query the database

Let's check in the template that the connection to the database and the table works :

/site/templates/comments.php
<?php

$comments = Db::select('comments');

foreach ($comments as $comment) {
    dump($comment);
};

Provided that the table contains any data, this should output several Kirby\Toolkit\Obj objects (one for each database row).

The page model

Now it is time to create a model that converts the data from the table into virtual pages:

/site/models/comments.php
<?php

use Kirby\Cms\Page;

class CommentsPage extends Page
{
    public function children(): Pages
    {
        if ($this->children instanceof Pages) {
            return $this->children;
        }

        $comments = [];

        foreach (Db::select('comments') as $comment) {
            $comments[] = [
                'slug'     => $comment->slug(),
                'num'      => 0,
                'template' => 'comment',
                'model'    => 'comment',
                'content'  => [
                    'title' => $comment->title(),
                    'text'  => $comment->text(),
                    'email' => $comment->email(),
                    'uuid'  => $comment->slug(),
               ],
            ];
        }

        return $this->children = Pages::factory($comments, $this);
    }
}

Here we redefine the children() method of the Page class to return the comments from the database as child pages.

Unless you have disabled UUIDs in your config, you need to pass a uuid field in the content array to prevent Kirby from generating the page in the file system when the $page->uuid() method is called.

If you generate the UUIDs automatically, as in the example above, they will change at every load. However, if you want to reference your virtual pages anywhere with their UUID, make sure to use a unique string that 1. does not change and 2. is not likely to be the same as another UUID in another page, e.g. a product SKU or something similar.

Accessing the comments in the template

With this page model in place, we can now access our comments as children of the comments page in our template:

/site/templates/comments.php
<ul class="comments">
    <?php foreach ($page->children() as $comment): ?>
    <li>
      <a href="<?= $comment->url() ?>">
        <?= $comment->text() ?> <small>by <?= $comment->email() ?></small>
      </a>
    </li>
    <?php endforeach ?>
</ul>

A template for the individual comment

To access individual comments on their own pages, we add a template for the comment:

/site/templates/comment.php
<?php snippet('header') ?>
<div class="comment">
  <?= $page->text()->kt() ?>
  <p><small>by <?= $page->email() ?></small></p>
</div>
<?php snippet('footer') ?>