Images manual sorting and ->first()

How can I get the first image if I manually sort my files?

With
$page->images()->first()->url()
I can get the first image of the page. But if I activate
files: true with sortable: true and arrange the images manually in the panel, it doesn’t do anything in the frontend. And also if I use $page->images()->sortBy('sort','asc') it makes no difference.

1 Like

You can do this:

<?php echo $page->images()->findBy('sort', '1')->url() ?>

or

<?php echo $page->images()->sortBy('sort', 'asc')->first()->url() ?>
2 Likes

Thanks for this. It works great. But why does it need sortBy and first?
The first suggestion works if there is manual sorting, but if there isn’t any manual sorting on a page the output breaks.

1 Like

The manual sort order is added to a meta file and that’s the only place that holds this information. Of course, you should always make sure that the page does not break by providing an if statement and a fallback solution. So if $page->images()->sortBy() is false, then fall back to $page->images()->first().

<?php 
if($page->hasImages()) {
  if($page->images()->sortBy('sort', 'asc')) { 
    echo $page->images()->sortBy('sort', 'asc')->first()->url(); 
  } else { 
    $page->images()->first()->url(); 
    } 
}
?>
2 Likes

That’s great. Thank you very much.
Now I understand…

Works great!

Is it possible to make a variable for this if-else statement?

So when I call the other fields of the image tag I don’t have to copy-paste this long php snippet.

You could create a snippet for that.

For example snippets/firstimage.php and paste the function @texnixe suggested there:

<?php 
if($page->hasImages()) {
  if($page->images()->sortBy('sort', 'asc')) { 
    echo $page->images()->sortBy('sort', 'asc')->first()->url(); 
  } else { 
    $page->images()->first()->url(); 
    } 
}
?>

Then everytime you need the “first image” function just call the snippet:

<?php snippet('firstimage') ?>

You can even add a variable to the snippet so you can overwrite the $page variable when you call it. This could be a select field with the children (See dynamic select options)
To hand over a variable to the snippet you write something like that:

<?php snippet('firstimage', array('imagepage' => $page->imagepage())) ?>

Another option would be a page model. The page model documentation even has a similar example: https://getkirby.com/docs/developer-guide/advanced/models#page-models-in-the-wild

1 Like

Another alternative would be to create a function:

<?php

function getFirstImage($page) {
  if($page->hasImages()) {
    if($page->images()->sortBy('sort', 'asc')) { 
      $image = $page->images()->sortBy('sort', 'asc')->first()->url(); 
    } else { 
      $image = $page->images()->first()->url(); 
    } 
 }
  return $image;
}
```

in your template:

```
<img src="<?= getFirstImage($page) ?>">
```

While a page model is only available for that page (type), a function (stored in plugins), can be called from anywhere. You could also define a new [page method](https://getkirby.com/docs/developer-guide/objects/page), which is also available anywhere.
1 Like

Really fascinating how many possibilities there are for one thing. What would be the best practice here, if there even is only one?

Maybe the page method since it’s not tied to a template, so that’s an advantage over the page model. But it probably comes down to personal preference, I guess.

Personally, I wouldn’t use the snippet method, but prefer either a plugin function or a custom page method if I want this functionality anywhere, and maybe a page model if I only need it for a specific page type.

But it also depends on the Kirby version you use. Page methods (2.3.0) were introduced later than page models.

Thank you very much!

I’ll dig into the function option, since I need it on a set of different pages.