Adding alt tag values dynamically via the Kirby panel

Hi,

In the Kirby starter kit, I see this code in the photography.php tempalte <img src="<?= $cover->crop(400, 500)->url() ?>" alt="<?= $cover->alt()->esc() ?>">

However, when I tried to add the alt tag in my template like this: <img src="<?php echo $page->images()->first()->url(); alt="<?= $page->alt()->esc() ?>">
The debugger showed: syntax error, unexpected token “=”

I’m trying to make it possible to add alt values to each picture via the Kirby panel. Grateful for your guidance and support-

You’re missing a ?>", you wrote:

<img src="<?= $page->images()->first()->url(); alt="<?= $page->alt()->esc() ?>">

but it should be:

<img src="<?= $page->images()->first()->url() ?>" alt="<?= $page->alt()->esc() ?>">

If you’re getting confused about these things, I’d recommend using an IDE, like VSCode, with syntax highlighting. So you’ll see immediately when bits are missing in your syntax.

In case of multiple attributes which need escaping, you might also consider using the attr() helper:

<img <?= attr([
  'src' => $page->image()->url(),
  'alt' => $page->alt()
]) ?>>

It’s also a bit strange that you’re getting the alt content from the page and not from the image.
Normally you’d have the alt text in the file’s content file, see: File blueprint | Kirby CMS

1 Like

Thank you, it worked fine. I added the code your provided <img <?= attr([ 'src' => $page->image()->url(), 'alt' => $page->alt() ]) ?>>

This is the yml file that I’ve for this specific page template. But I don’t see the ability to write the alt name in the Kirby panel.

title: stuhl
preset: page
num: zero

status:
draft: true
listed: true

fields:
Name:
label: Produkt Name
type: text

Beschreibung:
label: Beschreibung
type: text

Preis:
label: Preis
type: number
step: 0.01
before: €

I use VS code in my work but since I’m a beginner in PHP, I don’t know how to interpret the errors.

Since “presets” will be deprecated in the future, It would be better to rewrite the page blueprint without it. This also gives you the opportunity to learn about the options it had hidden:

title: stuhl
# preset: page # now discouraged
num: zero

status:
  draft: true
  listed: true

columns: 
  - width: 2/3    
    fields:
      Name:
        label: Produkt Name
        type: text

      Beschreibung:
        label: Beschreibung
        type: text

      Preis:
        label: Preis
        type: number
        step: 0.01
        before: €
        
  - width: 1/3
    sections:
      pages:
        label: Seiten
        type: pages
      files:
        label: Dateien
        type: files

By seeing all the options you can now decide to give a template to the files. For example if you intend to only have images, you could change the files section to something like this:

      files:
        label: Bilder
        type: files
        template: image # <--- add this

Then also add an image file blueprint:
/site/blueprints/files/image.yml (notice it’s in a “files” folder)

title: Bild

accept:
  mime: image/jpeg, image/png, image/gif

fields:
  alt: 
    type: text

Now, after you upload a new image through this section, it will have “Template: image”, and if you click on it in the panel, you’ll see the “alt” field.

You can echo that alt field in the page template file like this:

<img <?= attr([
  'src' => $page->image()->url(),
  'alt' => $page->image()->alt()
]) ?>>
1 Like

Many thanks for this detailed explanation which I just saw.

This code is not working well all the time:

 <img <?= attr([
  'src' => $page->image()->url(),
  'alt' => $page->alt()
]) ?>>

The debugger is saying: Call to a member function url() on null I don’t way it sometimes works and sometimes not.

Update: Kindly disregard my latest post concerning the yml file. I was able to make it work by decreasing the indentation.

It seems like not every page has an image.

The call to $page->image() returns null when Kirby doesn’t find any image in the page.

Think of null as “nothing”: you can’t get anything out of nothing, and trying to access methods or properties (in this case url()) on null therefore causes this error. Which makes sense, because you can’t have an URL to an image that doesn’t exist.

The solution to the problem is checking if the image actually exists, before trying to construct the <img> tag:

<?php if($page->image() !== null): ?>

  <img <?= attr([
    'src' => $page->image()->url(),
    'alt' => $page->alt()
  ]) ?>>

<?php endif ?>

by surrounding the html code of the image with an if statement which checks whether the image actually exists, you avoid calling ->url() on null, because that code is never executed when $page->image() is null.

The above code however isn’t ideal, because we call $page->image() twice, once only to check what it returns (in the if statement), and once because we actually want to use its return value.
Since we probably want to avoid calling $page->image() twice (Kirby has to do some work to find that image), you can also assign the image to a local variable, so you remember it:

<?php 

$image = $page->image();
if($image !== null):

?>

  <img <?= attr([
    'src' => $image->url(),
    'alt' => $page->alt()
  ]) ?>>

<?php endif ?>

That php block with the if statement has become a bit cumbersome, to make it shorter, you can also assign the variable and check if it’s null, all in one line, by taking advantage of the fact that in PHP “the result of any assignment operation is the value that has been assigned: ($a = $b) === $b”:

<?php if(($image = $page->image()) !== null): ?>

Notice the parentheses around the “assignment”. That’s better, but a bit ugly.
We can also exploit PHPs “implicit type coercion”: the if statement expects to get a boolean value (either true or false), so it converts any other value type it receives to one of those, essentially by guessing the developers intention. There are rules to this madness, but for us it suffices to know that null is converted (coerced) to false, and an image is coerced to true, therefore we can give the if statement the potential image itself:

<?php if($image = $page->image()): ?>

And this is also the form you normally see in the Kirby docs :slight_smile:

2 Likes

Many thanks indeed for this explanation. :slight_smile: :tophat: