Learn how to store more complex template code in controllers to separate logic from your HTML.
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.
Controllers go into /site/controllers
. Please 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.
The basic code for a controller is very simple. It's an anonymous function, which receives the $site, $pages and $page variables as arguments and should return any number of variables as associative array, which you want to pass to the template.
<?php
return function($site, $pages, $page) {
return array(
'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.
A typical example when 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 this in a controller. So let's create /site/templates/blog.php
and /site/controllers/blog.php
The controller will take care of fetching the right articles and add pagination to them. It will then pass an $articles
variable to the template to keep it nice and clean.
<?php
return function($site, $pages, $page) {
// get all articles and add pagination
$articles = $page->children()->visible()->flip()->paginate(20);
// add a tag filter
if($tag = param('tag')) {
$articles = $articles->filterBy('tags', '=', urldecode($tag), ',');
}
// create a shortcut for pagination
$pagination = $articles->pagination();
// pass $articles and $pagination to the template
return compact('articles', 'pagination');
};
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.
<?php snippet('header') ?>
<?php foreach($articles as $article): ?>
<!-- the code for each article goes here -->
<?php endforeach ?>
<nav class="pagination">
<?php if($pagination->hasPrevPage()): ?>
<a href="<?php echo $pagination->prevPageUrl() ?>">previous articles</a>
<?php endif ?>
<?php if($pagination->hasNextPage()): ?>
<a href="<?php echo $pagination->nextPageUrl() ?>">next articles</a>
<?php endif ?>
</nav>
<?php snippet('footer') ?>
If you are working with additional routes and you want to access the arguments from the router in your controller you can use the fourth argument to access an array of router arguments.
<?php
return function($site, $pages, $page, $args) {
// $args contains all arguments from the current route
};