For this recipe to work as described, you need to update your Kirby installation to release 3.1.3.
The standard way to filter (page) collections by tags or categories etc. is by using parameters in your URL. A typical URL usually looks like this:
When a website visitor opens this link in the browser, the controller checks if the URL contains a parameter or not and returns the corresponding collection. You can find an example in the "Filtering with tags" recipe.
While this works perfectly fine, some people prefer URLs like
http://example.com/blog/travel without the parameter separator or even without the parameter name, i.e.
How can we achieve this? Luckily, Kirby comes with a powerful router, which we can leverage for this purpose.
Let's go through this step by step.
First, we need a route that listens to our URL pattern.
blog/tag/(:any) with the
(:any) placeholder for the actual value will listen to URLs like
action closure, we render the
blog page and send the value for our tag in the methods's parameter array.
The actual filtering logic takes place in the Controller.
By loading the
$tag variable to our anonymous function, we can fetch the variable we passed to the
render() function in the route.
…we check if the
$tag variable is set and if so, we filter the articles by the tag's value, and finally return the
$articles variable to the template.
In your template, you can now loop through the
$articles collection and render the HTML for each article.
In case you use multi-word tags with spaces or special characters, you have to
urlencode() your tags in your tag links and
urldecode() them again in the controller.
If you want to leave out the
tag bit in the URL, you have to modify the route a bit:
In this case, tag values and subpages might conflict. First we therefore check if there is a subpage and return it if it exists. If not, we handle the value as tag and render the
blog page as in the route above.
In the examples above, we always return the blog page/template, only with a filtered set of subpages. If we want to use a different template for our tags or categories, we have to change our route and we need a new controller and template:
Within our route, this time we return a virtual page using the
Page::factory() method, because the page doesn't exist in the file system.
Here we use the
urldecode()d page slug as our filter value.