How do I load pregenerated thumbnails?

Hi there! Once again I’m running into a small problem regarding thumbnails and after several hours of research I’m at my wit’s end, so I hope someone in this forum can help me.

I want to create my thumbnails directly after I upload an image, mainly because the gallery script I use replaces images based on their suffix instead of using srcset (and also for peace of mind and site speed). Using a file.create:after-hook to generate several different sizes works fine, but when I try to use these pregenerated thumbnails in my templates like this

 <img src="<?= $image->thumb('xsmall')->url() ?>">

Kirby instead creates a new folder in media and generates one new thumbnail using the xsmall preset, ignoring the already existing thumb. Because of this the gallery script can’t find the other thumbnail sizes (because they haven’t been requested) resulting in missing images, the site is slow for the first time after I upload a bunch of new pictures and it also affects my server space, since each image now has a few duplicate thumbnails.
How can I “properly” generate thumbnails directly after an upload and how do I call them so that Kirby uses the correct folder/path? Any help would be greatly appreciated!

Hook:

 'hooks' => [
  'file.create:after' => function($file) {
      $widths = ['xsmall', 'small', 'medium', 'large', 'xlarge'];

      if($file->isResizable()) {
          foreach($widths as $width) {
              try {
                  $resizedImage = $file->thumb($width)->save();
              }
              catch (Exception $e) {
                  throw new Exception($e->getMessage());
              }
          }
      }
  },
  'file.replace:after' => function($file) {
      $widths = ['xsmall', 'small', 'medium', 'large', 'xlarge'];

      if($file->isResizable()) {
          foreach($widths as $width) {
              try {
                  $resizedImage = $file->thumb($width)->save();
              }
              catch (Exception $e) {
                  throw new Exception($e->getMessage());
              }
          }
      }
  },
],

Can you really pass sized like xsmall etc. to the thumb method? Never seen that…

The file.replace hooks uses a wrong variable name, should be $newFile: https://getkirby.com/docs/reference/plugins/hooks/file-replace-after

Apart from that, the code should actually work.

The if statement is not necessary, the FileVersion component checks that anyway.

1 Like

xsmall is just a thumb preset I use, to make the code a bit easier to read. :sweat_smile:

'presets' => [
  'xsmall' => ['width' => 640, 'height' => 640],
  'small' => ['width' => 800, 'height' => 800],
  'medium' => ['width' => 1024, 'height' => 1024],
  'large' => ['width' => 1600, 'height' => 1600],
  'xlarge' => ['width' => 2048, 'height' => 2048, 'quality' => 80],
  ],

I also changed the hook according to your suggestions:

'hooks' => [
  'file.create:after' => function($file) {
      $widths = ['xsmall', 'small', 'medium', 'large', 'xlarge'];

      foreach($widths as $width) {
          try {
              $resizedImage = $file->thumb($width)->save();
          }
          catch (Exception $e) {
              throw new Exception($e->getMessage());
          }
      }
  },
  'file.replace:after' => function($newfile, $oldfile) {
      $widths = ['xsmall', 'small', 'medium', 'large', 'xlarge'];

      foreach($widths as $width) {
          try {
              $resizedImage = $newfile->thumb($width)->save();
          }
          catch (Exception $e) {
              throw new Exception($e->getMessage());
          }
      }
  },
],

But I still get the same problem. I also tried to replace the files with the missing thumbnails, but only get this error:

Call to a member function type() on null

I did some further digging and found someone with a similar problem:

I tried to change my hooks to his suggestion, which also didn’t work. In the other topic @texnixe mentioned something about different image sources resulting in different timestamps, but I’m not shure where exactly I would generate a thumbnail from a resized image instead from the original file? Could it be that creating a collection causes some issues? I’m using this method to create the gallery:

<?php
  $snapshotPage = page('snapshots');
  $categories = $snapshotPage->children()->listed();
  $snapshots = new Collection();
  foreach ($categories as $c) {
   foreach ($c->images() as $i) {
       $snapshots->data[] = $i;
   }
  }
  $snapshots = $snapshots->sortBy('modified', 'desc')->filterBy('title', '!=', '')->paginate(25);
?>

Any new hints or information would be more than welcome, as I’m still absolutely lost what exactly the problem is.

What does this code have to do with the thumb generation? And why do you create this new collection when you can get all images of all categories with

$snapshots = $page->children()->listed()->images();

I tried to find a reason why the thumbs get a new timestamp/url and since the code for the thumbnail generation should be ok, I could only think of the collection causing some sort of issue. Apparently this train of thought was completely wrong, and I’m sorry if I caused any confusion with my post.

(As to why I create a collection instead of using images(): I’ve used this snippet since Kirby v1, not shure if images() was already available in this version, but I’ve updated my templates to this method now, thank you for mentioning it.)

Please check if you get the same error in a fresh Starterkit, where you just add the preset and hooks in the configs. Because I cannot reproduce the issue in a 3.5 Starterkit in my environment.

All thumbs are created as set in the preset.

I started with a fresh Starterkit, added the hooks and presets to config.php and also changed album.php to use thumb() instead of resize(), before uploading several images to different albums. Everything worked fine this way, but starting with a fresh Starterkit and replacing certain folders (assets/folder structure in content/blueprints/config/snippets/templates) caused the same issue to reappear.