Can't figure out how to display cover image

Hey community!

Really happy to finally work with Kirby. This is my first topic, and yes here’s a noob question :slight_smile:

Since many of my pages will use a very similar structure, I decided to configure the default page blueprint that looks like this:

title: Page
preset: page
fields:
  text:
    label: Text
    size: large
    type: textarea
sidebar:
  meta:
    type: fields
    fields:
      date:
        default: now
        type: date
  cover:
    headline: Cover
    template: cover
    type: files
  gallery:
    headline: Gallery
    template: gallery
    type: files
  files:
    headline: Files
    type: files

First off, this doesn’t work:

<?php if ($page->cover()->isNotEmpty()): ?>
Only show this if there is a cover image.
<?php endif ?>

Second, how do I show the cover image? I’m trying something like this:

<img src="<?= $page->cover()->url() ?>" srcset="<?= $page->cover()->srcset([300, 800, 1024]) ?>" />

Really appreciate the help!

Welcome :slight_smile:

First of all, checking that the field is not empty isn’t the safest way, you need to check the images physical existence before working with it. You should also set the min and max values to 1 in the blueprint so that it is not possible to pick more than one image in that field.

Something like this should do it…

<?php if($image = $page->cover()->toFile()): ?>
     <img src="<?= $image->url() ?>" alt="">
<?php endif ?>

You are using a files section, so there is nothing stored in your text file. You have to get the image via it’s template:

if($cover = $page->images()->template('cover')->first()) {
  // do something
}

Your code above and @jimbobrjames suggestion won’t work in this case.

1 Like

Yes, your right, what i posted would work on an files field, but my poor old eyes missed that this was a section.

:eyeglasses: (they don’t always help as I can tell from my own experience :slightly_smiling_face:)

2 Likes

Awesome! Now understanding the difference with storing files / content in text file.

Any reason why “multiple: false” isn’t working? I can still add multiple images to the cover.

cover:
    headline: Cover
    multiple: false
    template: cover
    type: files

Multiple is not an option for sections, only for files field. You can set a min and max value.

https://getkirby.com/docs/reference/panel/sections/files#section-properties

1 Like

Ah cool, thanks!

I’ve been trying to follow along with this and got pretty close but I’m stuck. Here’s my code:

<?php if($cover = $page->images()->template('cover')): ?>
<div class="post-cover"><img src="<?= $cover->url() ?>"></div>
<?php endif ?>

This is not generating a url and no image displays. Any ideas as to what I’ve got wrong?

@spanrucker Is there only one image with that template or multiple? In any case, your filter by template will return a collection (even if possible one with one member only) and not a single file object.

And a collection doesn’t have a url() method, you would have to use a foreach loop to go through the collection and then call the url() method on the individual items in the collection.

There is only one image with that template. So the function of the

->first()

in your code is to output only one file?

I added it and it works! Thanks, I think I understand more now!

Another option would be to use findBy()

<?php if($cover = $page->images()->findBy('template', 'cover'): ?>

Cool that works too, thanks @texnixe!

That’s the UUID of the file you chose in the cover image field.
You have to convert that field to a file.

<?php if($cover == $page->images()->findBy('template', 'cover')->toFile()): ?>
<img src="<?= $cover->url() ?>">
<?php endif ?>

Late to the party, but glad I found this thread. Have a likewise question but think I understand the matter. Just to be sure I’ll post & hopefully someone can give me heads up on this.

As all files are kept in the same folder for let’s say a project, choosing 1 file of those as cover can be done using a “cover” part in the blueprint and for all files a “gallery” part can be created, right? And am I right that to have only the file targeted as “cover” image it needs a different template?

See this blueprint as example (I removed other types for clarity):

title: Production

columns:
  main:
    width: 2/3
    sections:
      gallery:
        type: files
        layout: cards
        image:
          cover: true
        info: '{{ file.dimensions }} | {{ file.niceSize }}'
  sidebar:
    width: 1/3
    sections:
      cover:
        type: files
        label: Cover
        layout: cards
        image:
          cover: true
        required: true
        max: 1
        template: image
        info: '{{ file.dimensions }} | {{ file.niceSize }}'

And in the view it is called using the findBy method:

<?php if ($localVariable = $page->images()->findBy('template','cover')): ?>
  <img src="<?= $localVariable->url() ?>" alt="">
<?php endif ?>

Questions:

  • Is the variable $localVariable only local and thus can be any name?
  • Is the ->first() needed this way?

Yes, it can be named anything, it probably makes more sense to call it $cover or $coverImage, to make it clear to your future self what you are trying to fetch here.

The example will not return anything, I guess, because you are nowhere assigning this cover template (at least not in the part of the blueprint you are showing, where the gallery section is missing a template assignment, and the cover section has the template image assigned.

Where are you using first()? findBy() only returns a single element, i.e. the first element that it finds, so no, you don’t need first() in the example and you cannot even used first(), because first() is a collection method, not a single element (collection item) method.

Must be

image: page.images.findBy('template', 'cover')

@texnixe thanks for your quick response! I have to say that I’m not proficient in the Kirby language, coming from a handlebars environment…

I used

query: page.images.template('cover').first

which seems to work as well… but that’s is probably only because of the plural :slight_smile:

This is short for page.images.filterBy('template', 'cover').first().

FilterBy always returns a collection of images, hence you have to add first() to fetch the first image. Whereas findBy() return a single file object (as mentioned above). The documentation for each method usually tells you exactly what each method returns (there are exceptions where this is less clear, when methods are inherited from parent classes).

For example: $files->filterBy():

When the return type is a class, you can click on it and are redirected to the documentation for that class, with the methods available for this class.