Displaying image from photo album (folder of images) within a template

Have tried and tried and can’t figure it out.
I have a set of photo albums and I want each photo in an album to open as a page with previous, next and close actions. I just want to drop a bunch of images into a folder, have them show up as thumbs in album view (this is working) and each of them open as a page.
I can’t share the code here, new user “perks”.


So you want to be able to view images as if they were pages? This is possible, and is exactly what my Hepburn theme does.

The trick is to use a model for the album page to turn the images in virtual pages as if they were child pages of the album page:


class AlbumPage extends Page

    // Use images as pages
    public function children()
        $images = [];

        foreach ($this->images() as $image) {

          $images[] = [
              'slug'     => $image->name(),
              'num'      => $image->sort()->isNotEmpty() ? $image->sort()->value() : null,
              'template' => 'image',
              'model'    => 'image',

        return Pages::factory($images, $this);


Then you can use a template called image to display them. If you went to www.yourdomain.com/album/imagefilename it will display the image as if it was a page.

If you’re looking for a client-side solution, you could use a javascript lightbox like


Thanks! The models approach makes sense, meaning I can kinda understand how it works (not a developer). But I don’t know how to link to the images from the album thumbnails. I created the model and have renamed my single image template to image.php. Currently the thumbs are generated like so:
<div class=“thumbs”<?= attr(['data-even' => $gallery->isEven(), 'data-count' => $gallery->count()], ' ') ?>>
<?php foreach ($gallery as $picture): ?>

<?= $picture->resize(null, 160) ?>

<?php endforeach ?>

You need to wrap your image in a link tag, then set the href attribute to $page->url() . '/' . $picture->name().

The model turns the images into virtual pages, so from the album page, you can treat them like subpages. The model sets the images name() as the slug.

I use the sortby so i can reorder them in the panel, and the below gives you them in sort order rather than Alphabetical order.

$gallery = $page->children()->sortBy('num', 'asc')

Then you just link to the image like you would a normal page in the link tag.


The href part in my code above got turned into a link by the forum engine I guess.
I do now get the image slugs as mydomain.com/album/imagename but kirby throws an error when clicking through. I’m guessing the single image template is not working or used for some reason?

Once you are on the image pages themselves, for the next and previous buttons? You need to do a bit of trickery here in the controller for the image.php template.

something like this:

  // Get the album images
  $shotlist = $page->parent()->children()->sortBy('num', 'asc');

  // Image Index
  $shotidx = $shotlist->indexOf($page);

  // Next & Previous Navs
  $next = $page != $shotlist->last()  ? $shotlist->nth($shotidx + 1) : false;
  $prev = $page != $shotlist->first() ? $shotlist->nth($shotidx - 1) : false;

If you pass thouse to the template, youwill be able to use $next->url() and $prev->url() to make the image nav.

No, I never get to the image page.

Could you maybe put it up on Github, so we can see? there are a lots of seperate parts to this, so it would be difficult to share with us here by pasting the code.

Sure, here it is: GitHub - sandersolvak/web-solvak.ee: personal website

To clarify the setup: I have a “Photo” page that aggregates albums into a “feed” and I have separate album pages. The album page and the album block in the feed look identical. Ideally you could click on a photo from the Photo page and be taken directly to it, just like you would from the album page. The close button would take you to the album page - I figure making it behave differently depending on how you got there is too much hassle and makes it brittle.

album.php template:

		<div class="thumbs"<?= attr(['data-even' => $gallery->isEven(), 'data-count' => $gallery->count()], ' ') ?>>
			<?php foreach ($gallery as $picture): ?>
				<a href="<?= $picture->url() ?>">
					<?php echo $picture->parent()->images()->findBy('name', $picture->slug()) ?>
			<?php endforeach ?>

image.php template

	<div class="image">
		<img src="<?= $page->parent()->images()->findBy('name', $page->slug())->url() ?>" alt="" loading="lazy">

	<div class="controls">
		<a href="<?= $page->parent()->url() ?>" aria-label="Close">&times;</a>
		<?php if ($page->hasPrevListed()): ?>
		<a href="<?= $page->prevListed()->url() ?>" aria-label="Previous">←</a>
		<?php else: ?>
		<?php endif ?>

		<?php if ($page->hasNextListed()): ?>
		<a href="<?= $page->nextListed()->url() ?>" aria-label="Next">→</a>
		<?php else: ?>
	<?php endif ?>

And album controller:

return function ($page) {

    $gallery = $page->children();

    return [
        'gallery' => $gallery


That worked for everything except the prev-next links which I guess need work in the controller as pointed out above. Thanks so much so far!

The problem with the prev-next links is that your are checking for listed.

	<div class="controls">
		<a href="<?= $page->parent()->url() ?>" aria-label="Close">&times;</a>
		<?php if ($page->hasPrev()): ?>
		<a href="<?= $page->prev()->url() ?>" aria-label="Previous">←</a>
		<?php else: ?>
		<?php endif ?>

		<?php if ($page->hasNext()): ?>
		<a href="<?= $page->next()->url() ?>" aria-label="Next">→</a>
		<?php else: ?>
	<?php endif ?>

If you ignore listed, it works.

Its a bit tricky to explain but basically the model for the album page turns the files uploaded directly to the album page in child pages. When your looking at an individual image pages, Kirby is not aware of the sibling pages, because they are files not pages. The controller code i posted above fixes that, and your able to skim through them. Basically the image.php template cant see them as pages.

Its uses the images sort order instead of usual page numbering so that you can re-arrange the files and that has the effect of re-ording the virtual pages.

Nope, sorry, that is not the problem…

I think I need to add this example to the virtual pages guide…

Ok i didnt explain clearly enough… if you want to reorder them, you need to to use the images sort order, If your ok with ignore listed it does work, your right. I ran into this on my theme.

I think the model probably has to be extended to overwrite the listed method. But the listed status doesn’t really have anything to do with the sort order.

To make the sort order work, it would make sense to assign the the image sort field to the content of the page, then sort by this content field.

Then pass this sorted collection to prev/next to respect the sort order.