Get image focus in image snippet

I need to output the focus as CSS variables in an image snippet. The guidance in the documentation looks to be for outputting the image directly in the template, but I’m using a block which then calls the image snippet so I guess it needs to be in either the block or the snippet. I can get various attributes from the block like src and caption, but the focus info is in the image metadata file and I can’t see how to get to that. I’ve tried a few methods to get it but the only time I’m not getting PHP (not callable here mostly) errors I just get a file uuid by the looks of it.

I need to output the focus inside the image style attribute as css variables:

--crop-focus-x: [value]; --crop-focus-y: [value];

This is the image snippet:

<?php

$attrs = attr([
  'data-lightbox' => $lightbox ?? false,
  'href'          => $href     ?? $src,
]);

?>
<a <?= $attrs ?>>
  <img
    src="<?= esc($src, 'attr') ?>"
    alt="<?= esc($alt, 'attr') ?>"
    style="
      aspect-ratio: <?= $ratio ?? 'auto' ?>;
      object-fit: <?= ($contain ?? false) ? 'contain' : 'cover' ?>
    "
  >
</a>

And this is the image block that calls it:

<?php

/*
  Snippets are a great way to store code snippets for reuse
  or to keep your templates clean.

  Block snippets control the HTML for individual blocks
  in the blocks field. This image snippet overwrites
  Kirby's default image block to add custom classes
  and data attributes.

  More about snippets:
  https://getkirby.com/docs/guide/templates/snippets
*/

$src = null;

if ($block->location()->value() === 'web') {
    $alt = $block->alt();
    $src = $block->src();
} else if ($image = $block->image()->toFile()) {
    $alt = $block->alt()->or($image->alt());
    $src = $image->url();
}

?>
<?php if ($src): ?>
<figure class="<?= $block->width(); ?> <?= $block->spacing(); ?>">
  <?php snippet('image', [
    'alt'      => $alt,
    'contain'  => $block->crop()->isFalse(),
    'lightbox' => $block->link()->isEmpty(),
    'href'     => $block->link()->or($src),
    'src'      => $src,
    'ratio'    => $block->ratio()->or('auto')
  ]) ?>

  <?php if ($block->caption()->isNotEmpty()): ?>
  <figcaption class="img-caption">
    <?= $block->caption() ?>
  </figcaption>
  <?php endif ?>
</figure>
<?php endif ?>

In this case you need to either pass the $image variable to the image snippet and get the data from there, or you get the focus data from the image object and pass this data to the snippet.

I’ve been trying that, and just getting PHP errors. So clearly my PHP is years out of date or something!

EDIT: got a friend to help me, so posting the solution here in case anyone else has the same problem and is as bad at PHP as I am.

The snippet:

<?php

$attrs = attr([
  'data-lightbox' => $lightbox ?? false,
  'href'          => $href     ?? $src,
]);

?>
<a <?= $attrs ?>>
  <img
    src="<?= esc($src, 'attr') ?>"
    alt="<?= esc($alt, 'attr') ?>"
    style="
      aspect-ratio: <?= $ratio ?? 'auto' ?>;
      object-fit: <?= ($contain ?? false) ? 'contain' : 'cover' ?>;
      --crop-focus-x: <?php echo $focus['x'] ?>;
      --crop-focus-y: <?php echo $focus['y'] ?>;
    "
  >
</a>

The block:

<?php

/*
  Snippets are a great way to store code snippets for reuse
  or to keep your templates clean.

  Block snippets control the HTML for individual blocks
  in the blocks field. This image snippet overwrites
  Kirby's default image block to add custom classes
  and data attributes.

  More about snippets:
  https://getkirby.com/docs/guide/templates/snippets
*/

$src = null;

if ($block->location()->value() === 'web') {
    $alt = $block->alt();
    $src = $block->src();
} else if ($image = $block->image()->toFile()) {
    $alt = $block->alt()->or($image->alt());
    $src = $image->url();
}

$focus = $block->image()->toFile()->focus()->or('50% 50%')->value();
[$x, $y] = explode(' ', $focus);

?>
<?php if ($src): ?>
<figure class="<?= $block->width(); ?> <?= $block->spacing(); ?>">
  <?php snippet('image', [
    'alt'      => $alt,
    'contain'  => $block->crop()->isFalse(),
    'lightbox' => $block->link()->isEmpty(),
    'href'     => $block->link()->or($src),
    'src'      => $src,
    'ratio'    => $block->ratio()->or('auto'),
    'focus'    => ['x' => $x, 'y' => $y]
  ]) ?>

  <?php if ($block->caption()->isNotEmpty()): ?>
  <figcaption class="img-caption">
    <?= $block->caption() ?>
  </figcaption>
  <?php endif ?>
</figure>
<?php endif ?>


I’d move this part inside the if statement, otherwise you will get an error if the image doesn’t exist. And also define a focus for web images if needed

$src = null;

if ($block->location()->value() === 'web') {
    $alt = $block->alt();
    $src = $block->src();
    $focus = '50% 50%';
} else if ($image = $block->image()->toFile()) {
    $focus = $image->focus()->or('50% 50%')->value();
    $alt = $block->alt()->or($image->alt());
    $src = $image->url();
}

Thank you!