How to pass a varaible between pages?

I have a website with two type of pages:

  • item
  • collection: a list of items in a specific order.

An item can be in different collections, for example:
collection A: item A > item B > item C
collection B: item B > item C > item A

When the user navigates on the website, he pass through a collections page, click a collection, and then click an item.

On the Item page, how to display the collection which was clicked on the previous collection page (and the related items in that specific order, in a breadcrumb style)?


  • the user click on collection A, then item A, he lands on the item page with a breadcrumb like: collection A: item A > item B > item C
  • the user click on collection B, then item A, he lands on the item page with a breadcrumb like: collection B: item B > item C > item A

(I hope this is clear)
Thank you

You can probably just use this

Hello Lukas. No, breadcrumb is not useful here because it gives something like: Homepage > Items > Item A, which is not what I want.

How is the order inside the collections stored for your items? Or the other way around. How are the items assigned to the collections?

Edit: And how do you output these items / collections? A custom route or some params in the url?

The tree-structure of the content directory is:

+-- 1-items
    +-- 1-item-A
    +-- 2-item-B
    +-- etc.
+-- 2-collections
    +-- 1-collection-A
    +-- 2-collection-B
    +-- etc.

Then from a collection page I pick up a list of items with (blueprint of the collection page):

  label: Items
  type: structure
  style: table
    - item
      label: Item
      type: select 
      options: query
        page: items
        fetch: children
        flip: true

I was thinking about a custom route or params in the url, but that’s what I don’t know how to do?

So currently when you call the item page, there is nothing in the URL to indicate that the page was called from a collection page, right?

I think for your use case, a route would be the best option, so that you can then pick the virtual parent (i.e. the collection from the path in the URL), and then get the children by just looping through the structure field.

I don’t think a breadcrumb style navigation is the correct way of displaying those pages though, because the items are not children of the other items.

No currently there is nothing in the url.

Could you give an example of how to use routing in that case, please?

You could do something like this in your config.php.

c::set('routes', array(
    'pattern' => 'collections/(:any)/(:any)',
    'action'  => function($collection, $item) {
      return array('items/' . $item, compact('collection'));
1 Like

Note that you would have to make sure that your URLs contain the route. A page model would be the way to go here.

On a side note: With your setup, you will end up with the same content available at different URLs, which is bad for SEO. Are you taking care of this somehow?

Thank you guys,
I am trying to understand and make this work now.

About the url, I think, I would prefer an url like this: /items/:any/in-collection/:any

So that the default url would be items/item-a and I can put a link rel="canonical" on each duplicated content page. If there is no /in-collection part in the url, I would pick up a default collection.

How would be routes config in that case? Any idea or suggestion?

What is the first “any” supposed to be here?

this would be the item p.e.: items/item-a/in-collection/collection-a. Not sure if this makes sense though…

Does not really look like this makes sense. Your URL should be one of the following or similar:


1 Like

I used exactly this code:

which works fine when a correct url is reached (like colections/collection-a/resource-a). When the url is an wrong, it makes an error instead of a page 404 (because /items/wrong-slug doesn’t exists). How to fix that?

Argument 1 passed to Kirby::render() must be an instance of Page, boolean given, called in /kirby/kirby/component/response.php on line 27

Use an if statement to check if the page exists, otherwise redirect to the error page:

c::set('routes', array(
    'pattern' => 'collections/(:any)/(:any)',
    'action'  => function($collection, $item) {
      $page = page('items/' . $item);
      if($page) {
        return array($page->uri(), compact('collection'));
      } else {
        go('error', 404);
1 Like

This doesn’t make sense to me… Not everyone is going to visit your items through the collection pages. E.g. what if a user comes directly from a search engine? And as @texnixe mentioned, duplicate content is a pain for SEO.

If you really insist on doing so, have you considered cookies?

1 Like

Yes I agree it looks weird if the goal was strictly to access the /item-x pages. Here is the client requirement: make a website to presents several modules belonging to different curriculums. A module can belong to many curriculums. When you navigate to the page of a module, you should be able to go to the next module depending on the curriculum you chose in the first place. Does it make more sense?

  • I don’t think SEO duplicate is a problem if the link rel="canonical" points to an arbitrary default version. Or is it?
  • the /items and /items/item-x pages won’t be visible and therefore not directly accessible from the menu, so the default referenced version should be a /collection/collection-x/item-x page.

Does it make more sense to do it with cookies? If so, how would you do that?

Well, the question is if the items need to be accessible via the items page directly or not, and if so, then why?

The setup might make sense if the purpose if the items page is to avoid having to add the same content multiple times within the collections (if we think of these collections as a sort of categories to which an item belongs and where an item can belong to several categories).

Edit: question answered.

You should then block access to the direct (/items/item) URL as well (via server config, .htaccss, route or template) and only make those pages accessible via the collections.

1 Like