Routing
When you create a new page in Kirby's content folder, this folder creates a new URL, for example, the page /content/projects/project-a
will be available at https://yourdomain.com/projects/project-a
. So when the user types that URL into the browser's address bar, the project page will be rendered.
Sometimes however, you may want to provide content under URLs that do not exist as pages in your content folder, for example:
- to create virtual utility pages like a sitemap or an RSS feed,
- to redirect to other parts of your installation or to remove parts of a page URL to make pages available at a shorter URL (for example, leave out the blog folder when accessing posts that would otherwise be available at
https://yourdomain.com/blog/my-super-post
), - to create custom API endpoints,
- to return a response object,
- to filter by URL rather than using parameters,
- ...
That is where routes come into play. Routes react on an URL pattern. They can either return something to users when they visit an URL with that pattern, or they can have functional purposes, e.g. some function is executed when a script calls a particular URL.
Defining your own routes
Kirby has a built-in router, which can be extended with your own routes. Routes can be setup with the routes
option in your config or in plugins. Routes are simple associative arrays with two required fields: pattern
and action
.
In your config
In a plugin
You can also define your route definition as a callback, which gives you more control, e.g. to access information from inside Kirby in your patterns (in this example to use a Kirby option as part of the pattern):
Patterns
In your route patterns, you can use static, relative URL strings, e.g. some/static/url
, but also dynamic placeholders:
Placeholders can also contain expressions, e.g. ([a-z]+)
, and will be passed as arguments to the callback function in the order they appear:
If you want to use the same action for multiple patterns, you can either use regex expressions or pass an array of patterns:
When using placeholders like (:any)
and (:all)
or regex patterns, make sure that they are not too greedy and you accidentally catch routes you want left intact, resulting in things not working as expected anymore.
Example: A pattern like (:any)
will not only catch routes with a URL part like notes
or photography
, but also their JSON content representations notes.json
or photography.json
. In this case, using (:alphanum)
can be more suitable.
Response types
Depending on your use case, routes can return various response types, which will be handled accordingly by Kirby:
Page object
File object
String: HTML
Not found: false
, null
or ''
JSON from array
Response object
Exception
Methods
By default routes are only available for GET
requests. You can define additional request methods for the route:
CONNECT
DELETE
GET
HEAD
OPTIONS
PATCH
POST
PUT
TRACE
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.
Language scope
Since 3.2.0
In multi-lang installations, you can set a language scope for the route:
To make sure that translated slugs are automatically handled by Kirby, you can set a page scope:
In this example, we return the notes
page with the filter data. In your controller, you can now use this filter to return only the children with the given tag.
next()
Since 3.0.3
In some scenarios, you want to perform actions on all requests matching a route pattern, but then let the router find the next matching route. For this scenario you can use the $this->next()
call within your route.
This is perfect for the example above when you want to intercept URLs like https://yourdomain.com/photography-project-name
and create flat URLs. But at the same time you don’t want to break all the other pages. In this case you can search for the photography project in the route and if it doesn’t exist you can jump to the regular route for all the other pages with $this->next()
.
Pass data to controller
You can send additional data to the controller using the $page->render()
method:
You can then fetch this data in the controller.
Before and after hooks
You can register hooks for the event when a route has been found, but has not been executed yet, and when the route has just been executed. Those hooks are very useful to intercept certain routes based on your own rules, or to manipulate the result of a particular route.
route:before
route:after
Virtual Pages
A route can return a virtual page that doesn't really exist in the file system. This is very useful to mock pages with custom data from other data sources.
Removing the parent page slug from the URL
Sometimes we want to get rid of part of an URL for cleaner URLs, for example to replace the following URL
…with…
This can be achieved with the following two routes in your config.php
(or in a plugin):
Replace blog
with the slug of the parent page you want to remove from the URL.
Additionally, you can overwrite the $page->url()
in a page model to return the desired target URL when you use this method.