Skip to content

Controllers

Templates should contain as little code as possible to separate logic and form. With template controllers you can add more logic to your templates without messing up your markup.

TL;DR

  • Use a controller for the logic of your templates.
  • A controller must have the same file name as the corresponding template file.
  • Save controllers in /site/controllers.

The controllers directory

Controllers go into /site/controllers. Create the directory if it's not there yet. Controllers are named exactly like the templates they belong to:

Template Controller
/site/templates/article.php /site/controllers/article.php

Kirby will automatically load the controller for your template if it can find one.

Default controller

You can also have a default page controller: It works like a normal page controller. You only have to add it as /site/controllers/site.php. Be aware that the default controller only works as a fallback if no specific page controller for the template exists. It is not loaded in addition to the template-specific one.

Creating a controller

The basic code for a controller is very simple. It's an anonymous function that should return the variables that you want to pass to the template as an associative array.

<?php

return function () {
  return [
    'foo' => 'my first template variable',
    'bar' => 'my second template variable'
  ];
};

In this case the $foo and $bar variables will be available in the corresponding template.

Accessing Kirby objects in your controller

Like in templates, you can access the $site, $page, $pages and $kirby objects by loading them as arguments to the anonymous function. Kirby will magically inject the right objects for you:

A single object

return function ($page) {
    // do something with the page
};

Multiple objects

return function ($page, $site, $kirby) {
    // do something with the page, site and kirby
};

Order doesn't matter

return function ($site, $page, $kirby) {
    // do something with the page, site and kirby
};

A real world example

A typical example where a controller can come in handy is a blog template. Fetching the right articles can take a couple lines of code and it's much nicer to wrap these in a controller. So let's create /site/templates/blog.php and /site/controllers/blog.php

The controller

The controller will take care of fetching the right articles and add pagination to them. It will then pass the $articles and $pagination variables to the template to keep it clean.

/site/controllers/blog.php
<?php

return function ($page) {

  // get all articles
  $articles = $page->children()->listed()->flip();

  // add a tag filter
  if ($tag = get('tag')) {
    $articles = $articles->filterBy('tags', '=', $tag, ',');
  }

  // add pagination
  $articles = $articles->paginate(20);

  // create a shortcut for pagination
  $pagination = $articles->pagination();

  // pass $articles and $pagination to the template
  return [
    'articles' => $articles,
    'pagination' => $pagination
  ];

};

The template

With such a controller, the template can be super clean. A foreach loop for the articles and the prev/next pagination and you're done.

/site/templates/blog.php
<?php snippet('header') ?>

<?php foreach ($articles as $article): ?>
<?php snippet('article', ['article' => $article]) ?>
<?php endforeach ?>

<nav class="pagination">

  <?php if ($pagination->hasPrevPage()): ?>
  <a href="<?= $pagination->prevPageUrl() ?>">previous articles</a>
  <?php endif ?>

  <?php if ($pagination->hasNextPage()): ?>
  <a href="<?= $pagination->nextPageUrl() ?>">next articles</a>
  <?php endif ?>

</nav>

<?php snippet('footer') ?>

Arguments from the router

If you work with additional routes and you want to access the arguments from the router in your controller, you can use Kirby's route() method to access an array of router arguments.

<?php

return function ($kirby) {

  $args = $kirby->route()->arguments();
    // contains all arguments from the current route

};