Is it possible to use a template for files like images or pdf? Just retrieve the file list of a page and display them one by one in a template (eg for presenting images with exifs on new page without creating a subpage for each file)
Thanks!
Is it possible to use a template for files like images or pdf? Just retrieve the file list of a page and display them one by one in a template (eg for presenting images with exifs on new page without creating a subpage for each file)
Thanks!
Do you need a template for the page as such? If not, I think the easiest way to achieve that would probably be by pagination the image collection.
$image = $page->images()->paginate(1);
ha yes, good idea but I need a unique template for the file (itâs for displaying website mockups in full size, marvel/invision like)
A few options:
Put the file collection inside a subpage:
For instance:
parent/page/
  page.txt
  files/
    files.txt
    file1.pdf
    file2.jpg
    file3.svg
In the page.php template (and/or its controller), you can still retrieve the child 'files' page and its files to show at the /parent/page URL.
Then in the files.php template (and/or its controller), you can choose what to output. Maybe rely on a query string parameter, e.g. create URLs looking like /parent/page/files/?f=file2.jpg and use that parameter to render information about that file.
Variant for cleaner URLs: create a route for a pattern like (:any)/files/(:any), and in the associated function use the two parameters to retrieve the page and the file. If any of those donât exist, you will need to return the error page (I think some examples in the cookbook show how to do that). If both exist, return the parent/page/files page and pass it the file name as a parameter (not sure about the syntax from the top of my head).
Variant without a subpage: you can have the same kind of route â (:any)/files/(:any) â but just look inside the parent page instead of a child âfilesâ page. I think when you do that you should be able to render a template and return  a custom Response. Something like:
<?php
// site/config/config.php
c::set('routes', [
  ['pattern' => '(:all)/file/(:any)', 'action' => 'fileViewRoute']
]);
<?php
// could be a plugin script, for example:
// site/plugins/fileview.php
function fileViewRoute($pageUrl, $fileName) {
  $page = is_string($pageUrl) ? page($pageUrl) : null;
  $file = is_string($fileName) && $page ? $page->file($fileName) : null;
  if (!$page || !$file) {
    return page($kirby->get('option', 'error'));
  }
  $html = Tpl::load($kirby->roots->template() . '/file.php', [
    'page' => $page,
    'file' => $file
  ]);
  return new Response($html);
}
Note: I havenât run this code, Iâm just writing from memory and checking a few things in the docs.
I was just going to suggest the route alternative. Note that you probably have to pass some more variables you use in the head, e.g. the site object, when calling templates from a route.
I thought of a parameter but it seems a little bit overkill, I was hoping a âsingle.phpâ option (like wordpress). If I have to use the url, maybe is more simple to use the kirby parameters like this:
clientname/mockup:my_filename.jpg
And in mockup.php template use <img <?php echo param('filename') ?> /> where the image is needed?
Donât know if this approach is good or not.
You can use a URL parameter (Kirby-style or standard query string), thereâs no need for a custom route.
A custom route buys you two advantages at the cost of a bit of PHP code:
Another constraint: those page must be password protected. Donât know if it change anything.
The route technique seems good to me but if I understand the concept globally, I think itâs way above my coding level and I have hard time to really understand how routes work. The only things Iâve done with root is a little route copy/pasted from the doc and fortunatelly it worked.
Iâll try to understand the route solution but maybe itâs a little bit⌠perfectionnist for me 
Donât worry: The community is here to help!
OK, sooo⌠Iâm already stuck. I donât know how to link the route action and the plugin file. is it supposed to work atomatically? For the moment if I click on the /clients/client-name/filename.jpg it goes on /content/clients/client-name/filename.jpg.
I donât know why the content folder is exposed, I have constructed my url âmanuallyâ with <?php echo $page->url().'/'.$image->filename() ?> (and not $image->url()) maybe a route conflict?
The 'pattern' => '(:all)/clients/(:any)', doesnât seem to work, I also tried 'pattern' => '(:all)/clients/(:any)/(:any)', without results. I donât know how to test if the route works or not.
This is due to an internal Kirby route. I think you have to modify the URL a bit and use something like:
<?php echo $page->url() . '/imageviewer/' . $image->filename() ?>
Ok thank you, there is no more conflict, but I have an error page. Iâm really not sure how to make it work, how to link the plugin file and the route action, neither what the plugin file is doing 
The plugin file I suggested is just a script defining a function.
A route is two things: a URL pattern, and a function. When Kirby detects that the requested URL matches the pattern, it will call the function, passing it the value from any placeholders in the pattern â stuff like (:any) in the pattern.
You donât have to put it in a plugin file, itâs just a convenient place to store a function (because Kirby will load PHP scripts from site/plugins/*). You could put your function in index.php at the root of the site, for what itâs worth.
The âstandardâ way to define a routes function in Kirby is to put it directly in your config file:
<?php
// site/config/config.php
c::set('routes', /* array with one or several routes */ array(
  // And each route is itself an array with 'pattern' and 'action' keys
  array(
    'pattern' => 'hello/(:any)',
    'action' => function($urlFragment) {
      $content = 'Hello ' . $urlFragment;
      return new Response($content);
    }
  )
));
You can try the code above, and if you navigate to /hello/ or /hello/whatever you should see a simple message.
A few notes:
What pattern you use is up to you. I recommend using a part that is a little bit specific, like the /imageviewer/ part that texnixe suggested. So instead of trying to match on /clients/ (which describes your content), you should have a pattern like '(:all)/imageviewer/(:any)'
In your action function, you can name the parameters however you want. Iâve used different names in my exemples, but you can name them $a and $b if you want. Thatâs common to most programming languages (PHP, JS, etc.).
Your action function should return either a Kirby Page object (e.g. page('error') if your error page lives at content/error) or a Response object. You can make a HTML response easily with new Response('The HTML code').
Itâs possible that the example I provided (and did not test ;)) does not work because Kirby loads the config scripts first, then the plugin scripts (then the relevant controller and template and voilĂ ). Iâm not even sure it accepts a function name for the âactionâ parameter.  So maybe stick with keeping the function inline in the config script (like in my latest example and in the Kirby docs).
 So maybe stick with keeping the function inline in the config script (like in my latest example and in the Kirby docs).
Now, your main issue: youâre trying to show a page for an image but you have no page for the image. Thatâs why you have to find a workaround.
Workaround 1: make a page:
parent/page/
  page.txt
  gallery/
    image1/
      galleryitem.txt
      image1.jpg
    image2/
      galleryitem.txt
      image2.jpg
    image3/
      galleryitem.txt
      image3.jpg
If you do thatâ, youâre golden:
/parent/page/gallery/image1, it matches a real page in your content folder, thereâs no custom routing to do.galleryitem.php template.Only issue is: itâs a pain to edit.
Workaround 2: you reuse the pageâs template to show two very different types of content depending on a parameter.
parent/page/
  page.txt
  image1.jpg
  image2.jpg
  image3.jpg
Now you can do all the work in the page.php template, which will look like:
<?php
$image = $page->image( param('show') );
if ($image->exists()): ?>
 
  Let's show the image and the surrounding HTML content we want.
<?php else: ?>
  Let's show a full page with text, a list of small
  or medium images maybe, and each image should
  also be a link to /page/url/show:image_name.jpg
<?php endif; ?>
That means treating your template like itâs two templates in one.
Note: I used the image name in the URL but you can use an index instead, e.g. if your URL looks like /page/url/show:5, you can retrieve get the right image with $image = $page->images()->nth( param('show') );
Workaround 3: use a route, and in that route render a custom template (see above examples).
Upside: you have a bit more freedom with URLs, and you can keep your âproject pageâ and âbig image layoutâ templates separated.
Downside: you have to use a route, and Tpl::load() to render the âbig image layoutâ template.
Thanks, @fvsch, very thorough explanation 
yeah thanks, I will read that slowly and try to understand, seems great.
For the moment, I tried the param approach and I have to say that itâs pretty simple and straightforward, Iâll post my code later, and then try the route approach for my personnal culture.
And to answer this question:
This is possible with all methods. Just keep in mind that if you donât want images to be accessible, you will also have to implement an assets firewall as explained in the docs.
Some followup: I finished the mockup-presentation page, with access via direct url or login/pass. I used the parameters for now but I will look forward for the route solution. If youâre curious you can see the result here : http://judbd.com/espace-client/dummy-images
I hope I donât forget anything or leave huge breaches in my website 