Select image in Panel, access caption in template

With a blueprint, I made a “featured image” that an admin can choose with a select field in the panel. Here is the section from the blueprint:

  featured_image:
    label: Featured Image
    type: select
    options: query
    query: 
      fetch: images
      value: '{{url}}'
      text: '{{filename}}'

In the panel: I can successfully choose an image in the select and then save the choice. I can also edit the related image and add the caption.

On the template side, I can also successfully retrieve the url of the featured image and render the image out onto the page. However, I cannot figure out how to get the caption of the file.

This works and gets the url value of the image:

<?php echo $page->featured_image()->url() ?>

However, this does not work — it actually renders the url for some reason?:

<?php echo $page->featured_image()->caption() ?>

I’ve confirmed that the caption exists: there is, of course, the field in the panel, as well as the matching .txt file alongside the .jpg file in the content directory. I just cannot seem to pull the caption into the template?


For reference, here’s the full markup from the template:

<div class="featured-image">
	<img src="<?php echo $page->featured_image()->url() ?>" />
	<em><?php echo $page->featured_image()->caption() ?></em>
</div>

Sorry, ignore my previous comment.

I fiddled around a bit and found a solution for you. The problem is that the featured_image holds the {{url}} as a string and we want to get the actual $file object.

If you change the value to {{filename}}, you can create a Kirby $file object in the template with all the benefits from that (like getting the caption).

To do:

1 - In your blueprint, change the value in your query to: {{filename}} and add a ‘caption’ field to your files options if you haven’t got a caption field for files yet:


    files: true
        fields:
            caption:
                label: Caption
                type: textarea
    fields:
        featured_image:
            label: Featured Image
            type: select
            options: query
            query:
                fetch: images
                value: '{{filename}}'
                text: '{{filename}}'

2 - In your template, create a new $file object by calling $page->image(filename)


    <?php 
        /// Create a Kirby $file object with the filename found in the featured_image field
        // https://getkirby.com/docs/cheatsheet/page/image
        $image = $page->image( $page->featured_image() ); 
        
        // Since we now have a Kirby file object, we can get the URL and the caption! :)
    ?>

    <div class="featured-image">
	  <img src="<?php echo $image->url() ?>" />
	  <em><?php echo $image->caption() ?></em>
    </div>

The previous post looks good, but you can simplify the blueprint even more:

files: true
  fields:
    caption:
      label: Caption
      type: textarea
fields:
  featured_image:
    label: Featured Image
    type: select
    options: images

Brilliant. That does it!!! Thanks so much. Now the only issue remaining is getting that featured_image out on the stories listing page. I have a loop out on the main stories page that lists out all the story[s].

Here’s the snippet I’m trying to use but it currently just returns the name of the image file (without the full path):

<?php echo $story->featured_image()->url() ?>

Results in: http://127.0.0.1:8000/story-feature-image.jpg

Here is the full loop that I have:

<?php foreach($page->children()->sortBy('date','desc') as $story): ?>
    <div class="grid-item">
    <a href="<?php echo $story->url() ?>" class="story-item">
        <div class="feature-image" style="background-image:url('<?php echo $story->featured_image()->url() ?>');">
            <h2><?php echo $story->title()->html() ?></h2>
            <em><?php echo $story->date('F d, Y') ?></em>
        </div>
        <?php echo $story->intro()->kirbytext() ?>
        <div class="view-story"><span class="ghost-btn">View this story <i class="fa fa-arrow-right"></i></span></div>
    </a>
    </div>
<?php endforeach ?>

Same here, you need to create a file object:

echo $story->file($story->featured_image())->url();

woah. that did it. so what exactly is that doing? Why does it have to be a file object before I can get the value of the featured_image()->url()? Does the file object provide the path?

You need to tell Kirby to get an image/ images of a page with the $page->file() , $page->files() methods, e.g.

$page->file()

without any parameter would return the first file object in the folder.

If you add a parameter:

$page->file('myfile.jpg')

you can fetch a specific image object.

In your example, what you get in your file, is the filename of the cover image. Now you tell Kirby to fetch that file from the folder and echo the url with the url() method which is a method of the file class.

Instead of the file() method, you can also use the image() method, if you prefer that.

$page->image('myimage.png')

You can read this up in the docs.

1 Like