How to properly overwrite a kirby tag?


I’d like to overwrite the “image” kirby with my own code to use a CDN/Image Optimizer and deliver the images via that instead.

While just doing my own image kirby tag and completely circumvent the original one is easy enough, i’m looking for a solution to still use the “original” one as a fallback and especially as the finally rendering of the img tag. I don’t want to reimplement all the things kirby does anyway for images, I just need a different URL basically.

Also thought about using kirbytag:before and :after hooks, but then I need to parse too many things by own instead of having all the attributes parsed and delivered to me.

For the Kirby 2 Plugin I used some really dirty hack (see ) to keep a reference to the original HTML generator and use that in the end. But maybe there’s a better solution I could use for that while rewriting the plugin for Kirby 3.

Any ideas/input would be very welcome


I think the correct way in K3 is via a plugin (not sure if the old /tags/ folder still works)
In my site I overwritten both (link: and (image: tags.
A good starting point is something like this

Kirby::plugin('manu/zendo', [

        # Overwrite the default (image:) tag
        'image' => [
            # All the available attributes
            'attr' => [
                // All the other attributes

            # Generate and return some html
            'html' => function ($tag) { // Some code here }

I used the native (image:) code as a starting point.

EDIT: here’s a link where you can find more information about extending kirbytags

EDIT PART 2: Only now realised you want to keep the old one as a fallback. Not really sure you can do that natively, unless you re-implement the old code as a fallback inside the “new” tag itself

EDIT PART 3: I was looking at your old code and I think an alternative could be to simply replace part of the native image tag rather than storing the entire original implementation. Because if the goal is to implement an image coming from the CDN, you still want to keep the same code for the remaining part (caption, alt attributes, likes and all that stuff.)

Similarly to what you have done in Kirby 2, you should be able to get the original tag like this:

$tag = Kirby\Text\KirbyTag::$types['image'];
1 Like

Thanks alot for the input. In the meantime I found , which should be the right approach (there’s the cloudinary plugin, which also uses that), BUT my former approach uploaded the image to the CDN, if it didn’t exist there yet and then updates a field with the right reference. Now when I do that within that function, it runs into an infinite recursion in \Kirby\Cms\ModelWithContent::update, resp. \Kirby\Cms\ModelWithContent::commit, resp. \Kirby\Toolkit\Properties::propertiesToArray where it calls $this->$name() for “url”, which calls that file::url again and where I try to find that reference, which isn’t there yet and so on…

I’m out of ideas right now how to prevent that (except uploading the image to the CDN at another point than in “file::url”)

I have not tested this specific use-case, but it might work if you call the lower-level $file->save() method instead of $file->update().

Oh, yes, that works. Thanks a lot. What’s the difference then between update() and save(), just to satisfy my curiosity

update() is a high-level function that does validation based on the blueprint, runs permission checks, runs hooks, flushes the cache etc.

save() is the low-level function that just saves the new data. It is run by update() internally once the validation has passed.