How do I create a query to list all images used on a page?

How do I create a query to list all images used on a page (in the backend)? In the .txt, the images are located in different areas, e.g. layouts, blocks, structures… These also have completely different field names. I don’t want to list all images that are in the page folder, because not all of them are used.

I would like to automate my current solution, as currently all images are selected manually. This is time consuming and error prone.

This similar post is for Kirby 2 and the link is no longer available.

What you can do (assuming you are storing all images with their file uuids):

Write a script that fetches all file UUIDs via regex patterns from each content file, then get the file object for each UUID.

Ideally, you would cache the results, so you don’t have to do this on each page call.

You can wrap this logic in a method that you could then use as query in the Panel.

Thanks for the solution approach. When my PHP knowledge deepens, I will be able to write the code. However, I am still a leap year away from that.

Is there a comparable solution here on the forum or in the cookbook that I can use as a basis? I don’t expect a copy-and-paste solution, as I also want to understand and learn what I’m doing.

Yes, all images have a UUID, so I would have a concrete search scheme.

Not sure, definitely not in the cookbook, but this should get you going:

// read the raw file content into the $content variable
$content = F::read($page->contentFile()); 
// regex pattern for file UUIDs
$regex = '/file:\/\/[A-Za-z0-9]+/i';
// do a preg_match_all, $matches returns the matches
preg_match_all($regex, $content, $matches);
// $matches[0] contains all full matches
$fileUuids = $matches[0];
// loop through file uuids and try to get a file object from the page
foreach ($fileUuids as $uuid) {
  if ($file = $page->file($uuid)) {
    echo $file->filename();
  }
}

If the file can be anywhere in the site instead of in the current page only, you need to use $site->index()->files() instead.

In your case, you don’t want to echo the files, so collect them into a new files collection instead:

$files = new Kirby\Cms\Files();
foreach ($matches[0] as $uuid) {
  if ($file = $page->file($uuid)) {
    $files->add($file);
  }
}
dump($files);
1 Like

Now you’ve already told me a copy-and-paste solution :clap:
That worked like a charm, I didn’t expect that. Thanks!

Only the image names where output, but I will still manage the output of thumbnails. The basic framework works.

But I could still need a little push: It will also output the cover: - file://qOikm2TXiOvHjcmL
(only serves as a preview image for the panel). Sure, it is also in the .txt. file. So you still need to integrate a filter that excludes the cover.

Not me, you :stuck_out_tongue:

Well, if you simply exclude the cover and image used in the cover field is also used in the rest of the content, then it gets more complex, and you need to loop through all fields but the cover field separately.

1 Like

I had to laugh at myself :rofl:

Yes, I also noticed earlier that it will be difficult. But the start was so easy.
The output of the thumbnails also worked great.
Then I noticed that some images appear 3x in the list. This is because occasionally an image is used as a cover, in the article and as a meta image. Fortunately, I was able to solve that. But the problem with the individual filter leads me back to my original solution of selecting the images manually. :man_shrugging:
But I learned something and will keep the new snippet well.

Not difficult, just more complicated, so here you go:

<?php
// get fields from blueprint, exclude the one you don't want
$fields = array_filter($page->blueprint()->fields(), fn($field) => $field !== 'cover', ARRAY_FILTER_USE_KEY);
$regex = '/file:\/\/[A-Za-z0-9]+/i';
$fileUuids = [];
// loop through the field and fetch value from page
foreach ($fields as $field) {
  $value = $page->{$field['name']}()->value();
  preg_match_all($regex, $value ?? '', $matches);
  $fileUuids = array_merge($fileUuids, $matches[0]);
}

$files = new Kirby\Cms\Files();
// only unique file uuids
foreach (array_unique($fileUuids) as $uuid) {
  if ($file = $page->file($uuid)) {
    $files->add($file);
  }
}
dump($files);
1 Like

You took my slip of the tongue too literally, because you presented me again a working copy-and-paste solution. :ok_hand:

The output of the image names does not show cover images anymore. I will still add additional filters, as sometimes the meta-image and other unneccessary images still shows up.

I am VERY satisfied and have learned something new! :technologist:
Thank you!