Routing

Kirby has a built-in router, which can be extended with your own routes.

Routes can be setup with the routes option in your /site/config/config.php
Routes are simple associative arrays with two required fields: pattern and action.

Example:
c::set('routes', array(
  array(
    'pattern' => 'my/awesome/url',
    'action'  => function() {
      // do something here when the URL matches the pattern above
    }
  )
));

Patterns

URL patterns for routes can be static, relative URLs: some/static/url or parts of the URL can be defined by dynamic placholders:

Placeholder Matches
(:any) Matches any character and stops at the next /
(:num) Matches any number and stops at the next /
(:all) Matches everything from here on until the end or the next placeholder

Placeholders can also contain expressions. i.e. ([a-z]+)
Placeholders will be passed as arguments in the order they appear.

// my/awesome/pattern/(:any)/(:num)/(:all)
function($anyPlaceholder, $numPlaceholder, $allPlaceholder) {

};

If you want to use the same action for multiple patterns, you can either use regex expressions or pass an array to the pattern:

c::set('routes', array(
  array(
    'pattern' => array('blog/(:any)', 'events/(:any)'),
    'action'  => function() {
      // do something here when the URL matches the pattern above
    }
  )
));

Multi-language setup

In case of multi-language sites you must call the $site->visit() method in order to activate the selected page and set a language.

c::set('routes', array(
  array(
    'pattern' => 'my/pattern',
    'action' => function () {
      return site()->visit('some/page', 'en');
    }
  )
));

Actions

The action must be a valid callback. An action must either return a page object, a response object, redirect to a different URL or exit the code execution by returning false.

Returning a page

function() {
  return page('some/page');
}

Returning a page with additional data for the template

Sites without multi-language setup

function() {

  // additional data for the page
  $data = array(
    'foo' => 'bar'
  );

  return array('some/page', $data);
}

Multi-language sites

function() {

  // additional data for the page
  $data = array(
    'foo' => 'bar'
  );

  // activate the page and set the language
  site()->visit('some/page', 'en');

  return array('some/page', $data);
}

To access data from a route in a controller, you can use a fourth parameter.

Returning a response object

function() {
  return response::json(array(
    'some', 'json', 'stuff'
  ));
}

Redirecting

function() {
  return go('some/page');
}

Stopping the app

function() {
  f::download('download.zip');
  return false;
}

Methods

By default routes are only available for GET requests. You can define additional request methods for the route like this:

c::set('routes', array(
  array(
    'pattern' => 'my/awesome/url',
    'action'  => function() {
      // do something here when the URL matches the pattern above
      // and the specified request method
    },
    'method' => 'GET|POST|DELETE'
  )
));

Multiple routes with different actions

If you need multiple routes, add them within the routes array. Do not use multiple c::set() commands, otherwise the other routes will be ignored.

c::set('routes', array(
  array(
    'pattern' => 'my/first/url',
    'action'  => function() {
      // do something here when the URL matches the pattern above
    }
  ),
  array(
    'pattern' => 'my/second/url',
    'action'  => function() {
      // do something else here when the URL matches the pattern above
    }
  ),
  array(
    'pattern' => 'my/third/url',
    'action'  => function() {
      // do another thing here when the URL matches the pattern above
    }
  )

));

2.4.0 +

Hosts

Since Kirby 2.4, routes can also be restricted to match only on a specific host:

c::set('routes', array(
  array(
    'pattern' => 'my/awesome/url',
    'action'  => function() {
      // do something here when the URL matches the pattern above
      // and the specified request method
    },
    'method' => 'GET',
    'host'   => 'getkirby.com'
  )
));

Simulating Wordpress URLs

When you previously had your blog running on Wordpress you are probably used to URLs for your articles like this:

http://yourdomain.com/2012/12/12/my-awesome-article

It's difficult to achieve the same URL structure for a Kirby-based blog. In Kirby it's more usable to have every article in a single blog or articles folder, which results in a more simple URL scheme:

http://yourdomain.com/blog/my-awesome-article

The router can help to simulate the Wordpress blog scheme, while still using Kirby's flat article structure.

/site/config/config.php
c::set('routes', array(
  array(
    'pattern' => '(:num)/(:num)/(:num)/(:any)',
    'action'  => function($year, $month, $day, $uid) {

      // search for the article
      $page = page('blog/' . $uid);

      // redirect to the article or the error page
      go($page ? $page->url() : 'error');

    }
  )
));

Omitting the blog folder in URLs

A similar approach can be used to omit the blog or article folder in the URL entirely, if you are aiming for something really clean for your blog:

Instead of…

http://yourdomain.com/blog/my-awesome-article

…you can achieve…

http://yourdomain.com/my-awesome-article

…with the following two routes:

c::set('routes', array(
  array(
    'pattern' => '(:any)',
    'action'  => function($uid) {

      $page = page($uid);

      if(!$page) $page = page('blog/' . $uid);
      if(!$page) $page = site()->errorPage();

      return site()->visit($page);

    }
  ),
  array(
    'pattern' => 'blog/(:any)',
    'action'  => function($uid) {
      go($uid);
    }
  )
));