Skip to content

Content Representations

Content Representations allow you to output the content in different formats. Be it JSON for your frontend JS library of choice or to use Kirby as an API for other tools, an automatic RSS feed representation of your blog or a plain text representation of your résumé.

Creating a representation

In this example, we will create a JSON representation of the default template. After we are done, all pages with the default template will also be available in JSON. We will see below how exactly that works.

A representation is defined by its representation template. For our JSON representation, let's create a file default.json.php in our /site/templates directory with the following content:


$data = [
  'title' => $page->title()->value(),
  'text'  => $page->text()->kirbytext()->value()

echo json_encode($data);

You can of course output anything in the representation template. As we are building a JSON representation in our example, the output should be valid JSON.

The response will automatically be sent with the content type application/json.

A content representation requires that the standard template with the base name is present. If you want to create a JSON representation project.json.php, make sure that project.php exists. If project.php doesn't exist, Kirby will fall back to default.json.php, and if that template doesn't exist either, return the error page.

That means, a content representation is always a variant of the standard template. If you don't need the standard template at all, you can use this instead of the representation to return the content type you need. In this case, send a header with the corresponding content type.

Representation types

In most cases, you don't have to send a content type header manually, Kirby will do this for you based on the representation type (based on extension and/or content). If you use some custom extension, Kirby will assume a default content type of text/html. In case you want to set a specific content type, you can do this with response types, for example:


// send a `text/plain` response type
// code to generate article hash:
// $hash = ...

echo $hash;

Accessing the representation

Now that we have a representation template for our default template, we can request all default pages as a JSON file. To access the representation, add the name of the representation to the end of the URL. becomes and so on.

If you use content representations on the homepage, the URL will be for a JSON representation (replace home with the name of your home page if you have set the home option in your config).

If the representation exists, the template will be loaded and Kirby will send a correct content type header if possible. If the representation doesn’t exist, the error page will be displayed like if you didn’t use content representations at all.

It is still possible to create pages that contain a dot in their URL. If you already have a page called about.json for some reason, it will continue to work. You can get the JSON representation of that page at Please keep in mind though that using dots in URLs is not recommended to avoid confusion.

The built-in PHP server has issues with dots in paths, unless they are part of a filename, and will throw an error. For this reason, you may have to explore other local development solutions when working with content representations.

Representation controllers

You can also have dedicated controllers for each of your representations. If you create a controller with the name default.json.php, it will be used for the JSON representation of the default template. If no dedicated representation controller exists, the standard controller (default.php or site.php) will be used instead (if available).

Representations in plugins

You can create content representations in plugins by defining a template with the matching extension.


Kirby::plugin('your/feed', [
    'templates' => [
        'notes.rss' => __DIR__ . '/templates/notes.rss.php'

If you need a matching controller, you can create one via a plugin as well:


Kirby::plugin('your/feed', [
    'templates' => [
        'notes.rss' => __DIR__ . '/templates/notes.rss.php'
    'controllers' => [
        'notes.rss' => function () {
            // put your controller code here

Controllers and templates from plugins get overridden automatically if they exist in the templates or controllers directories. You can use this behavior to provide default setups in a plugin and still give the option to overwrite them individually if needed.