Can you list content from subpages of another page?

#1

Can you list content from subpages of another page?
E.g. the following site structure:

  • Home
  • Products
    • Product
    • Product
    • Product

Would it be possible with Kirby to retrieve the pictures of the different products from the “Products” subpages in the “Home” template and display them on the “Home” page? What PHP code would you need?

#2

Yes, that is possible, you can fetch any page using the page() helper, e.g.

if ($page = page('products')) {
  $images = $page->children()->images();
  foreach ($images as $image) {
    echo $image;
  }
}

will print all images from all subpages of the products page.

#3

What should the code look like for a particular image called “productpic”? So if you want to display just the specific “productpic”-images from the “product”-subpages (one per page) on the homepage instead of all the images?

#4
$images = page('product')->children()->images()->filterBy('name', 'productpic');

should do the job. At least if that’s what the image is called. Or is that an image selected in a field?

Then something like this:

$images = page('product')->children()->images()->filter(function($image) {
  return $image->parent()->fieldname()->toFile() === $image;
});

replace fieldname() with the name of the field that contains the image.

#5

When i try the following code

<?= $images = page('products')->children()->images()->filter(function($image) { ?>
<?= return $image->parent()->productpic()->toFile() === $image; ?>
<?= } ?>

i get this error message:

syntax error, unexpected 'return' (T_RETURN)

The parent page is called “products”, so I used this name as the root page. The “product” pages all have different names.

#6

That’s not the code I posted above… Why did you add all the echo statements? I’m defining a variable there, so you should leave the code as is.

But I forgot to close my parentheses again, corrected above.

#7

Sorry. I had no intention of changing anything, it’s just programmer’s inability (yet). I assumed that <?= would be the same as <?php.

<?php if ($page = page('products')) { ?>
  <?php $images = page('products')->children()->images()->filter(function($image) { ?>
  <?php return $image->parent()->productpic()->toFile() === $image; ?>
<?php }); ?>
  <?php foreach ($images as $image) { ?>
   <?php echo $image; ?>
  <?php } ?>
<?php } ?>

works great.

I also need the page title of the subpage as image caption, how can I retrieve it from the same subpage additionally?

#8

You really shouldn’t use the syntax above. If you want to use curly braces, don’t close your php tags and open them on a new line again. If you want to start with a new tag, use the following syntax (with colons and endif/endforeach)

<?php if ($page = page('products')): ?>
  <?php 
  $images = page('products')->children()->images()->filter(function($image) {
    return $image->parent()->productpic()->toFile() === $image; 
  });
  ?>
  <?php foreach ($images as $image): ?>
   <?php echo $image; ?>
  <?php endforeach ?>
<?php endif ?>

But actually, if you don’t use any HTML tags in between, your code would be better off like this:

<?php 
if ($page = page('products')) {
  // this is the beginning of a variable definition using a filter with callback
  $images = page('products')->children()->images()->filter(function($image) {
    return $image->parent()->productpic()->toFile() === $image; 
  });  // it ends here and shouldn't be interrupted with new PHP tags

  foreach ($images as $image) {
    echo $image; 
  }
}
?>

And certainly don’t start a new php tag in the middle of a closure.

<?= is a short echo tag, that is the same as <?php echo and is actually preferable to the long version.

#9

OK, i’ll try to consider that in the future.

I also need the page title of the subpage as image caption, how can I retrieve it from the same subpage additionally?

#10

You can get it via the parent() method from the image:

$image->parent()->title();
#11

With the following code it works on the homepage:

<?php if ($page = page('products')): ?>
  <?php $images = page('products')->children()->images()->filter(function($image) { return $image->parent()->productpic()->toFile() === $image;  }); ?>
  <?php foreach ($images as $image): ?>
  <div class="card">
         <div class="card-body">
               <?php echo $image; ?>
         </div>                         
         <div class="card-footer">
               <a href="#" class="stretched-link"><?php echo $image->parent()->title();?></a>
         </div>
  </div>
  <?php endforeach ?>
<?php endif ?>

However, all texts inserted from the homepage “home.txt” that follow this code are no longer displayed. All texts prior to it are. I didn’t notice this at first, because I didn’t scroll down.
Any idea why that might be?

#12

Because $page is now the products page, you should use a different variable for the products page.

Also, once the variable is defined, you might as well use it:

<?php if ($products = page('products')): ?>
    <?php $images = $products->children()->images()->filter(function($image) { return $image->parent()->productpic()->toFile() === $image;  }); ?>