Decide subpage after creating page

I’m building a website for a magazine. It has several categories that are currently listed in a select field in the article blueprint. This means that all articles are created in the same folder and have the same parent, however are filterable by the category select field. Ideally URLs will be ‘’. Is this possible with a route? Or is there a way I can choose the article’s parent after they’re created instead of it being a subpage?

The reason for this structure is that we went all articles to be listed together in the panel (in Drafts, Unlisted, and Listed sections). I considered the PageTable plugin but there’s no way of adding a page with this.


Yes: Filtering via routes | Kirby CMS

I’m struggling to get my head around how filtering via route helps here as my category pages exist and show relevant articles using a collection. The problem I’m having is that articles in the collection are not children of the category. Does this make sense, or is there a better of doing this routes rather than with collections?

So you have category pages and a blog page with articles? But if you do already filter them in the article pages, why do you need an additional filter? I’m probably missing something here.

There is no ‘blog’ page. My explanation is probably lacking somewhat, sorry! I’ll try a different angle…

I have a category page that lists articles from a collection. I have four different categories in total, here’s an example of one of the collections for one of the categories:

return function ($site) {
    return $site->children()->filterBy('category','Visual');

The url for this example would be However, when I click on an article from this page it would go to instead of as the articles are not subpages of the category. Is it possible using routes to add the category to the URL like this, without having to have the article as a child page of the category?

I have to think about this. Maybe use a page model that returns the category url instead of the standard URL of the page in conjunction with a route that listens to (:any)/(:any), where the first placeholder is the category and the second the page id.

Ok, thank you. Maybe I’m going about this the wrong way though. The reason it is structured this way is so when you log in to the panel you’re presented with all articles in ‘Drafts’, ‘Unlisted’, and ‘Listed’ sections and you can add a new article via the ‘Drafts’ section. I could list all pages using the PageTable plugin and make all articles children of their categories to get the desired URLs, but then I can’t add a page without choosing its category first (something we want to avoid).

Looks like all your articles are direct children of /content. In your first post you said they all have the same parent, that’s why I thought they were in a blog folder (or whatever that folder is named). Personally, I wouldn’t want them to be all children of the $site object and be all mixed up with other stuff, but that’s just my 2ct.

1 Like

True. If you need to change a category later, that would indeed be an issue because currently you cannot move pages out of the box yet (although there would be ways to achieve this).

If you can’t get the model and route to work, let me know.

Am I right in thinking I need to look at the ‘Overriding the Page class’ example and do something like:

class ArticlePage extends Page {
    public function url() {
        return ...

I get

localhost is currently unable to handle this request

Whenever I add url() to the page model, even if I’m not trying to load that specific page.

You url method needs the same signature als the original: public function url($options = null): string

Thanks, I managed to get this working. Here’s my model:


class ArticlePage extends Page {
  public function url($options = null): string {
    return url($this->category()->lower() . '/' . $this->slug());

And here’s my route:

    'pattern' => '(:any)/(:any)',
    'action' => function ($any, $page) {
        return page($page);

Unless you see a problem somewhere here? Thanks (again) for all your help!