Hi everybody!
I’m asked to create online booklets for existing productions. All data for a production - so those for the booklet as well - is put in the production blueprint, which has three tabs; one for the normal content, one for playdates and one for the booklet content. Some data is shared, like the title, credits, cover, playdates. Audiences should get a link to the booklet by QR code like .../productionname/booklet
.
Spitting through the docs and seeing Routes | Kirby CMS I thought that would work by having a route like
'routes' => [
[
'pattern' => 'productions/(:any)/booklet',
'action' => function ($slug) {
return page('productions/' . $slug);
}
]
]
but then I need to pass in the applicable parts as params, and keep the ones I don’t need out. Is this possible?
At first I was hoping that I could write logic in the production.php
template to only show the parts of the booklet based on the url but I’m not sure if that’s an option.
Creating a virtual page with its own template booklet.php
like doesn’t have the direct connection anymore with the “linked” production so I can’t get the data from the production anymore. Or do I miss something obvious?
'routes' => [
[
'pattern' => 'productions/(:any)/booklet',
'action' => function ($slug) {
return Page::factory([
'slug' => $slug,
'template' => 'booklet',
'model' => 'booklet',
'content' => [
'title' => 'Online booklet of ' . $slug,
]
]);
}
]
]
Is routes a good way to get this scenario working, or is there a better alternative?
I think I need some sample material as I’m new to routes & controllers 
@texnixe which of the routes is best to take; the first one or the one which creates a virtual page?
Just for starters I have a controller booklet.php
<?php
return function ($page) {
$slug = urldecode($page->slug());
return [
'slug' => $slug
];
};
So what do I pass in when my production blueprint results in a txt
with:
summary: {text field}
credits: {structure field}
cover: {file}
special: {structure field}
For the booklet I want special
as extra and I don’t want credits
.
First one, definitely, rendering the page as you did, but with the additional data passed to it.
As arguments in the anonymuos function, then use the data you pass to the controller from the route. See the example in the guide I linked above.
See how the $data array contains an item called ‘tag’, which you then pass to the arguments in the controller.
I’ll defenitely give that a shot.
Am not sure how I can exclude data in the controller… so it won’t be rendered.
Why don’t you create different snippets with the content you need for each version. Then you just pass the snippet name as parameter and all good, without a complicated list with a, b, c…?
But you could of course also do something like this:
$data = [
'summary' => true,
'credits' => false,
// etc.
];
Okay, before I sign off after a long day this is what I’ve got so far… it’s not working for me and at the same time I feel like going in circles. I don’t seem to get the original data passed in. The output of the $data array using dump($data)
in the template is just 0 and 1 instead of the actual values from the txt file.
'routes' => [
[
'pattern' => '(:all)/booklet',
'action' => function ($slug) {
$data = [
'summary' => false,
'layout' => false,
'credits' => false,
'playdates' => false,
'cover' => true,
'synopsis' => true,
'booklet' => true,
'videostrip' => true,
'castandcrew' => true
];
return page($slug)->render($data);
}
]
]
Results in the template using dump($data)
:
Array
(
[summary] =>
[layout] =>
[credits] =>
[playdates] =>
[cover] => 1
[synopsis] => 1
[booklet] => 1
[videostrip] => 1
[castandcrew] => 1
I don’t know what to put in the controller. A dump placed in the controller does not give any output.
<?php
return function ($page, $data) {
return dump($data);
};
For reference: the blueprint of a production has this data (excerpt):
----
Synopsis: <p>Eurydice is certainly not your typical type of fairy tale.</p>
----
Videos: [{"content":{"url":"https://vimeo.com/753778733","caption":""},"id":"cc85ec69-32be-4f02-8693-49082a026aee","isHidden":false,"type":"video"}]
----
Castandcrew:
-
name: Pencil
profile:
- file://OUwGXYpwIT43WiLT
bio: "<p>The pencil is a hard working necessity. Without it you really can't make any notes.</p>"
----
Year: 2022
----
Credits:
-
role: Concept and Direction
name: Celine Daemen
-
role: Virtual Art Direction
name: Aron Fels
You need to pass each variable in the data array to the function separately, exactly like I wrote above, so
return function ($page, $summary, $whatever) {}
And as explained in the docs:
After a good nights sleep I made the decision of just creating one boolean in the config which can be checked in the controller, to make it easier for me to see how this is passed on.
After a lot of trial and error I have a working solution and a better understandig of the way controllers work. Thanks @texnixe!
For anyone like me starting out with routes and controllers here is the code for such a switch controlling data from one source into two coupled ‘pages’.
Config:
'routes' => [
[
'pattern' => 'productions/(:any)',
'action' => function ($slug) {
$data = [
'booklet' => false
];
return page('productions/' . $slug)->render($data);
}
],
[
'pattern' => 'productions/(:any)/booklet',
'action' => function ($slug) {
$data = [
'booklet' => true
];
return page('productions/' . $slug)->render($data);
}
]
]
In the production.php
controller I make the $booklet
variable a boolean to work with:
<?php
return function ($kirby, $site, $page, $booklet) {
$booklet = $page->booklet()->toBool();
};
In the production.php template I use the value of the $booklet
variable to render out parts of the data from the txt
file of the production using snippets:
<?php
if ($booklet === true) {
snippet('booklet');
} elseif ($booklet === false) {
snippet('summary');
snippet('layout');
snippet('playdates');
?>
Funny how simple it is, really. If you know it.
Not quite. When I remove the first code block there is an error because the production page doesn’t know what the variable $booklet
is. But the second codeblock indeed is superfluous. How about that. In earlier tests I got errors but that was because I named my controller production.php
so the booklet.php did not respond. By naming the controller generic it works. And without the toBool();
method. Sweet.
As a side note: even when I remove the whole controller it still works, so only the codeblock in the config is needed. Or is this caching in action? I’m a bit hesitant about this development… either way if it lkeeps working it should be fine. But I’m not fully confident why it works. So there’s a bit of learning still for me on routes & controllers 
Not really sure what codeblock in the what config you mean. The routes?
Indeed, the codeblocks in the config I mentioned are those of the routes.
I’m closing this issue as it is solved by @texnixe as usual 
In the end it was simpler than I expected. I really like the way Kirby’s codebase is structured. And the support is a strong USP as well.