Permalinks for resized images

Hej,

I have a question about permalinks.

We have a Kirby site online. A blog article was created, and an image was uploaded to it. Thereafter, we created a newsletter outside of Kirby. We copied the URL of the resized image directly from the source code of the website, inserted it into the newsletter, and sent the newsletter.

Unfortunately, it turned out afterward that Kirby changed the image URL again. We did not upload a new version of the file.

As an example:
/media/pages/current/study-plant-meals-standard-in-university-menus/8ffb2a11b3-1686819575/buffet-canteen-asian-eleonore-h-adobe-stock-660x.webp

This URL later became this:
/media/pages/current/study-plant-meals-standard-in-college-menus/8ffb2a11b3-1687436810/buffet-cantine-asian-eleonore-h-adobe-stock-660x.webp

This is, of course, fatal because numerous newsletter recipients now no longer see a picture.

I checked if we could use a permalink that does not change. My understanding is that a UUID URL should never change. So in the case of an image, something like /@/file/kF4qTSbqnFAUEkEw

But with such a URL, I only get the original image—not the resized image.

My questions:
Why did Kirby change the URL again?
Is there any way to make sure that a URL does not change again?
Wouldn’t it be cool if the permalink could trigger a resize directly by parameter? Something like /@/file/kF4qTSbqnFAUEkEw/300 to stay in the example above.

Think of the media folder as a cache. It doesn’t make sense to link to it directly.

If you absolutely need to, you can change the page hash that is used, but then you lose the cache invalidation for the file: content | Kirby CMS

What I would do instead is use a route for this purpose that returns the file in the format you need. Then you can pass the parameters as needed as well.

You could create your own mini thumb server, here is a very basic example

use Kirby\Http\Response;

return [
'routes' => [
	[
		'pattern' => 'thumbserver/(:any)',
		'action'  => function ($fileUuid) {

			$file = site()->index()->files()->findBy('uuid', 'file://' . $fileUuid);

			if ($file) {
				$width  = get('width') ?? 200;
				$height = get('height') ?? 200;
				$format = get('format') ?? 'jpg';
				$crop   = get('crop') ?? false;

				return Response::file($file->thumb([
							'width'  => $width,
							'height' => $height,
							'crop'   => $crop,
							'format' => $format,
						]
					)->url());
			}

			return null;
		},
	],
],
];

Then in your template, just echo the url:

<img src="<?= url('thumbserver/d2mcgqZ8fKNNyN8E?width=400&height=400&crop=center&format=webp') ?>" alt="">

Instead of using the path to page and filename, you could also work with the file UUID.

This approach might even work well for headless setups, I guess.

Note that anyone with a file uuid can create any sizes of thumbs using this route, so this is a bit of a security issue. Or you would have to limit the possible sizes to those you use anyway, but in any case this needs some restrictions that prevent malicious people from doing evil things.

For images in newsletters it might be better to upload them to your newsletter service and serve from there, or move the relevant files manually to the assets folder (and serve from there), or load images via CDN, or as I mentioned above change the token and lose the cache invalidation…

Thank you very much for the explanations and even a code snippet!

Based on your snippet I will work out my solution. I think security can be handled quite well with a whitelist of allowed parameter values.

Thanks a lot!

I forgot to add the use statement at the top of the file, edited above.