<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Moinframe - Posts</title>
		<description>Practical tutorials and code examples for Kirby CMS developers. Learn about plugins, panel customization, dev workflows and quick tips from the moinframe YouTube channel.</description>
		<link>https://moinfra.me/posts</link>
		<atom:link href="https://moinfra.me/posts.xml" rel="self" type="application/rss+xml" />
		<language>en</language>
		<lastBuildDate>Sun, 03 May 2026 00:00:00 +0200</lastBuildDate>
					<item>
				<title>Love for the Underdog</title>
				<link>https://moinfra.me/posts/love-for-the-underdog</link>
				<guid>https://moinfra.me/posts/love-for-the-underdog</guid>
				<pubDate>Sun, 03 May 2026 00:00:00 +0200</pubDate>
				<description>
					<![CDATA[A little over a year ago, in February 2025, I launched moinframe. But the wish to share my excitement for Kirby with more people had been brewing for years before that. 	Let's take a quick trip down to memory lane. 	I found Kirby CMS back in version 2, looking for a proper home for my photography …]]>
				</description>
				<content:encoded>
					<![CDATA[<div style="height: 1.25rem;"></div><div class="text has-size-6 has-text-">
	<p>A little over a year ago, in February 2025, I launched moinframe. But the wish to share my excitement for Kirby with more people had been brewing for years before that.</p></div>
<div class="text has-size-6 has-text-">
	<p>Let's take a quick trip down to memory lane.</p></div>
<div class="text has-size-6 has-text-">
	<p>I found Kirby CMS back in version 2, looking for a proper home for my photography portfolio and blog. Back then, WordPress was the obvious choice, and to be fair, WordPress is what introduced me to the whole world of self-hosted websites in the first place. I owe it that.</p></div>
<div class="text has-size-6 has-text-">
	<p>But a predefined theme was never my dream. So I dug into the theme files pretty quickly, met the famous WordPress Loop, and realized: nope. Everything is a post, the syntax, widgets and the markup ends up tangled with the logic in ways I never got comfortable with. It worked, but it never clicked, as the cool kids say. Even though I wasn't a developer back then.</p></div>
<div class="text has-size-6 has-text-">
	<p>Then I found Kirby. A flat-file CMS, written in PHP, no database, no themes, no opinions about how my templates should look. A whole stack of friction was just gone.</p></div>
<div class="text has-size-6 has-text-">
	<p>The Panel was clear and customizable, all fields were the simple yaml structure we still use and love.</p></div>
	<figure class="has-text-left" style="--aspect-ratio: auto; --object-fit: contain; --max-width: none;">
					
<picture data-lazyload>
            <source
            type="image/webp"
            data-srcset="https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-400x220-crop-blur0-q70.webp 400w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-800x440-crop-blur0-q70.webp 800w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-1200x660-crop-blur0-q70.webp 1200w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-1600x880-crop-blur0-q70.webp 1600w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-2000x1100-crop-blur0-q70.webp 2000w" sizes="100vw" />
        <img
        loading="lazy" decoding="async" fetchpriority="auto"        width="4608"
        height="2538"
        src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20xmlns:xlink=%22http://www.w3.org/1999/xlink%22%20viewBox=%220%200%20100.00%2055.00%22%3E%3Cfilter%20id=%22b%22%20color-interpolation-filters=%22sRGB%22%3E%3CfeGaussianBlur%20stdDeviation=%221%22%3E%3C/feGaussianBlur%3E%3C/filter%3E%3Cimage%20filter=%22url%28%23b%29%22%20x=%22-2.5%25%22%20y=%22-2.5%25%22%20width=%22105%25%22%20height=%22105%25%22%20href=%22data:image/jpeg%3Bbase64%2C/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gNTAK/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgxIyUdKDozPTw5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/9sAQwEREhIYFRgvGhovY0I4QmNjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Nj/8AAEQgANwBkAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5%2Bv/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5%2Bjp6vLz9PX29/j5%2Bv/aAAwDAQACEQMRAD8A218IaEZSpsCQeP8AWP8Az3VMfBmgEY%2Bw/wDkV/8AGtfO2QkxuTngrnH86nBJGSMexoAwf%2BEM0H/nx/8AIr/40f8ACGaD/wA%2BP/kV/wDGt6kbd/Dj8aAOcfwhoav/AMeXH/XVv/iqafCWgkYNif8Av83/AMVXRCMO5Y5yPeneWtAHM/8ACHeH/wDnxP8A3/b/AOKo/wCEO8P/APPif%2B/7f/FV03lrR5a0Ac2vgzw%2Bw/488H085/8A4ql/4Qrw/wD8%2Bf8A5Gk/xro/LWjy1oA5z/hCvD//AD5/%2BRpP8aP%2BEK8P/wDPn/5Gk/xro/LWjy1oA53/AIQ7QgABZtgekz/40VvMMMQKKAH%2BXjOHYZOcDH%2BFLsP/AD0b9P8ACn0UAJSMit1GadRQBXdir8NjPalDN3Jx%2BP8AhSORvI37T6CjB/56tQA7P%2B23/fJoyP7zf98mm4P/AD1b8qMH/nq1ADuD3b/vk0Z/22/75NJnA%2B8xP1pcr/ef86ADP%2B23/fJoz/tt/wB8mjK/3n/Olyv95/zoAa3Ddc0UjHJ4ooAsUUUUAFFFFAGdfT3EEoMFnJcjnOx0XB/4ERUR1C%2ByR/ZVx9fNi/8AiqvSIXc4JA9QaXYf8mgCG0uJ50Yz272xBwA7K273%2BUmrGf8AbH5U3Yfb86Nh9vzoAdn/AGx%2BVGf9sflTdh9vzo2H2/OgB2f9sflRn/bH5U3Yfb86Nh9vzoAQ0UEYooAsUUUUAFFFFAFaRd0mcnjtgc0bV9B%2BVFFACgAdKOKKKAGgksQVIA6HPWncUUUAHFHFFFABRRRQB//Z%22%3E%3C/image%3E%3C/svg%3E"
        data-srcset="https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-400x220-crop-blur0-q70.jpg 400w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-800x440-crop-blur0-q70.jpg 800w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-1200x660-crop-blur0-q70.jpg 1200w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-1600x880-crop-blur0-q70.jpg 1600w, https://moinfra.me/media/pages/posts/love-for-the-underdog/463aaa239d-1778255274/kirby-cms-version-2-panel-2000x1100-crop-blur0-q70.jpg 2000w"
        sizes="100vw"
        alt="kirby-cms-version-2-panel"
         />
</picture>		
					</figure>
<div class="text has-size-6 has-text-">
	<p>Image handling was easy, too. Of course with one necessity: the Focus Plugin developed by <a href="https://flokosiol.de" target="_blank">Flo</a>, which was an amazing helper on image heavy layouts.</p></div>
	<figure class="has-text-left" style="--aspect-ratio: auto; --object-fit: contain; --max-width: none;">
					
<picture data-lazyload>
            <source
            type="image/webp"
            data-srcset="https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-400x220-crop-blur0-q70.webp 400w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-800x440-crop-blur0-q70.webp 800w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-1200x660-crop-blur0-q70.webp 1200w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-1600x880-crop-blur0-q70.webp 1600w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-2000x1100-crop-blur0-q70.webp 2000w" sizes="100vw" />
        <img
        loading="lazy" decoding="async" fetchpriority="auto"        width="4608"
        height="2538"
        src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20xmlns:xlink=%22http://www.w3.org/1999/xlink%22%20viewBox=%220%200%20100.00%2055.00%22%3E%3Cfilter%20id=%22b%22%20color-interpolation-filters=%22sRGB%22%3E%3CfeGaussianBlur%20stdDeviation=%221%22%3E%3C/feGaussianBlur%3E%3C/filter%3E%3Cimage%20filter=%22url%28%23b%29%22%20x=%22-2.5%25%22%20y=%22-2.5%25%22%20width=%22105%25%22%20height=%22105%25%22%20href=%22data:image/jpeg%3Bbase64%2C/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gNTAK/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgxIyUdKDozPTw5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/9sAQwEREhIYFRgvGhovY0I4QmNjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Nj/8AAEQgANwBkAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5%2Bv/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5%2Bjp6vLz9PX29/j5%2Bv/aAAwDAQACEQMRAD8A1/8AhEdD5/0M8/8ATV/8aP8AhENDP/Ll/wCRX/xrcrk5/G8ENw0awq6g43ByP0xQFzR/4RLRP%2BfL/wAiP/jTT4O0InJsj/39f/Gq0PjSxfHmYj/76P8ASr8fibSXXJusH02N/hQK6IP%2BEN0H/nyP/f5/8aP%2BEN0H/nyP/f5/8asN4m0dR/x9H/vg1Rm8aaamdjM//ASKAuib/hDdB/58j/3%2Bf/Gj/hDdB/58j/3%2Bf/Go9L8Upqd6LaGDqMltx4/SuioGYi%2BDNBwD9hz6/vn/APiqkXwV4fb/AJhzD389/wD4qtoDKrlSRk8inrsXoJB%2BBoAxP%2BEI8Pf8%2BB/7/Sf40f8ACEeHv%2BfA/wDf6T/GtzcPST8qUEHs9AGIPBegYx9hYAf9N5P/AIqit5Onf8aKAKlY8Vrai6UiCLPP8IrXrCiuM3YGfWpYFPxXZQytZ4jUY3dB9Kr2um2ax7jCrH04Gat69KC9r/wL%2BlM2f6MjGMTrLgbVPXNNu0TO16lht/o2ntAG8h4ZBgZIwGJ7Vh3OjxL0WtMajf6fqUz6hOWtUO1FcDgkjBAz0HP4U2e8inJkiOUblT6ippt7PUdaKWq0E8H2iw3Nw4HKuF/TNdrGdyZriNFn2XUqgnDSHgd%2BBXZWT%2BZbK3qTT15mODvEpa5HqMhthYXSW4BO4suSeRWXcX/iDT71Lf7TBc7kD7mUjuRjr7Vr6tceS1sDwWP9RWRqd1F/aUZkfaCgGcZ7mqKJ5tX19YS6CzbHBAzkfrWK%2BveIZLqKJpljDuF%2BUdM1Nd6s1lLG8ksMlqRuMI%2BZmJPBzj0wcZ7VVlv45GimjPRwwNAHo1m5kgBYkn1NFVdEmE9kWBzhyM/gKKAJK4SK%2B/07r0LD9a7uuGHhXVRctJugwWJHznv%2BFJol3Gazdb2t8NggNz%2BVUG1BdOjR7eZxcYI2FjtYHvj1GTWneeFtWn2bTbnbn7zn29qonwTrEkpkle3Ynk/vD/hRa6sxRTTuY088124W4faOevRTUmmyDaY1kBbBb0AAGTWs3gnV3J3Nb85/5aE/0oTwVq8YfYbYFxgnzDwO46UkrLQuaUmULK7aK5LBiDknIP0r0Hw/J5ukxvnPJ/nXHr4L1cNndb/9/D/hXY6BZT6fpUdvclTIrEnacjk1XUiCa0KPiezv7mazayt3lVN24r25FYl9puutOssWnzFgmARjg8%2B9ehwHCY56%2BlSE4GeaCzyM%2BHNdaTc2nyNIeSTj%2BVSL4f10QLGdOlypJzgD046%2B3616sFXO4DmnA59aAMPwhb3drpLx3sLRSecSFb0wOf50VuUUAU6KKKACiiigAooooAKKKKALEH%2Br/GpaKKACiiigAooooA//2Q==%22%3E%3C/image%3E%3C/svg%3E"
        data-srcset="https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-400x220-crop-blur0-q70.jpg 400w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-800x440-crop-blur0-q70.jpg 800w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-1200x660-crop-blur0-q70.jpg 1200w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-1600x880-crop-blur0-q70.jpg 1600w, https://moinfra.me/media/pages/posts/love-for-the-underdog/c696d60c57-1778255275/kirby-cms-version-2-file-view-2000x1100-crop-blur0-q70.jpg 2000w"
        sizes="100vw"
        alt="kirby-cms-version-2-file-view"
         />
</picture>		
					</figure>
<div class="text has-size-6 has-text-">
	<p>With php 5.3 (ha!) in the backend, I could built anything. A client gallery with password-protection, a pricelist with token based authentication (via url query). I even used the <code>params()</code> method for displaying child page content.</p></div>
	<figure class="has-text-left" style="--aspect-ratio: auto; --object-fit: contain; --max-width: none;">
					
<picture data-lazyload>
            <source
            type="image/webp"
            data-srcset="https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-400x220-crop-blur0-q70.webp 400w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-800x440-crop-blur0-q70.webp 800w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-1200x660-crop-blur0-q70.webp 1200w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-1600x880-crop-blur0-q70.webp 1600w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-2000x1100-crop-blur0-q70.webp 2000w" sizes="100vw" />
        <img
        loading="lazy" decoding="async" fetchpriority="auto"        width="4608"
        height="2538"
        src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20xmlns:xlink=%22http://www.w3.org/1999/xlink%22%20viewBox=%220%200%20100.00%2055.00%22%3E%3Cfilter%20id=%22b%22%20color-interpolation-filters=%22sRGB%22%3E%3CfeGaussianBlur%20stdDeviation=%221%22%3E%3C/feGaussianBlur%3E%3C/filter%3E%3Cimage%20filter=%22url%28%23b%29%22%20x=%22-2.5%25%22%20y=%22-2.5%25%22%20width=%22105%25%22%20height=%22105%25%22%20href=%22data:image/jpeg%3Bbase64%2C/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gNTAK/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgxIyUdKDozPTw5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/9sAQwEREhIYFRgvGhovY0I4QmNjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Nj/8AAEQgANwBkAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5%2Bv/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5%2Bjp6vLz9PX29/j5%2Bv/aAAwDAQACEQMRAD8A9AooooAKpm8tIpmBmO8HBBLH9KuVgqVGoXBIy28gGs6kpRtYqKXU1DqFqpw0uPqpqxG6yIHQ5VhkGsS6KPEQ3px7VYtrueO1iVLKWRQF%2BYEcjHaphOTdmDUbaGrTHQPjJYY9Diq5ubghmSzfAwArsATwT2zx0H51a7c1sSRrCFYEO/HYscVIBgUtFABRRRQAUUUUAFFFFABXJakJRfTNA4Vt5yCODzXW1VfT7WR2d4QWY5JyayqwlK3Ky4OKvzHJAXUsgM8ihR2Uda6azV/IhZVb7o5B46VL/Zln/wA8B%2BZqyipFGFXCoowPalThNSvJjk4WtFCbH/56n8hTlDDq2fwpFkRjhXUn0Bp9bGYUUUUAFFFFABRRRQAUUUUAFc/e%2BLLWyu5LeS1uWZGK5ULg49Oa6CuWv9LtLu8Mx1SFBvLFcr37daTdhpXLlz4nt7e5mhNpcuYWCsyhcZPQDJp114kt7eXy2tLl/lVsqq45APc%2B9Z974cW8vpLpNRRUlIbaFBHTjndVu70Brk8XyohRQU8vPRQPX2o1EWX1yzgKloZE3RrJnCjAIz6%2B9Ttq8CiM7JCJFDKRjv8AjWTqGiG4u7dhq6wi3jVDHgYbA5z83cUt/wCH3v3t3h1QRLDGFwsYIYjv96mLU1H1eKO0W4aGfDAELgbuuMdauW8y3EKyqrKG7MOaof2Y/kxx/aFKrGUOUzu569au2cBtrZIi%2B8rn5sYzk5oGT0UUUAFFFFABRRRQAVyYvREhg8osWPXjBoornryska048xQnspJXDgcGNO/%2ByKu3WozWd80Rt2dNqYKuB/CO1FFbR1Rm9GSTavHDLJGWZHfY3rgFEP51Vl1B45I5Yy2yRCxYKCT8zepFFFCirsLmoL2c2VvLGAVeMnkc5yfetfTmd7JGkGGOcj8TRRTsk7hfQs0UUUxBRRRQB//Z%22%3E%3C/image%3E%3C/svg%3E"
        data-srcset="https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-400x220-crop-blur0-q70.jpg 400w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-800x440-crop-blur0-q70.jpg 800w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-1200x660-crop-blur0-q70.jpg 1200w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-1600x880-crop-blur0-q70.jpg 1600w, https://moinfra.me/media/pages/posts/love-for-the-underdog/b21b688795-1778255275/kirby-cms-version-2-params-2000x1100-crop-blur0-q70.jpg 2000w"
        sizes="100vw"
        alt="kirby-cms-version-2-params"
         />
</picture>		
					<figcaption>
				Each polaroid is it's own page, but only displayed in the /polaroids page.			</figcaption>
					</figure>
<div class="text has-size-6 has-text-">
	<p>Here is the thing: Kirby did not turn me into a developer overnight. No software will, AI won't.</p></div>
<div class="text has-size-6 has-text-">
	<p>Kirby just did not get in the way. And I think that is the biggest trait.</p></div>
<div class="text has-size-6 has-text-">
	<p>Simple enough to start with as a designer, deep enough to grow into when I was ready. That is a rare combination. And this promise is kept over the last 10+ years.</p></div>
<div class="text has-size-6 has-text-">
	<p>Of course, Kirby was never the loud option. Every couple of months, the dev scene picks a new winner. When I started developing seriously, React was the new kid on the block. Then Next.js. Then headless everything. With round trips to Strapi and other Content Management Systems it always made work and setup more complex, while the output was not improving. In the size of projects I worked on anyways.</p></div>
<div class="text has-size-6 has-text-">
	<p>Now there is AI everything. If you sit there with a flat-file CMS and tell people it is what you build with, you can feel the polite skepticism in the room. Is that a real Gamechanger? Will that make me 30% more performant?</p></div>
<blockquote>
  Spoiler: it is not. It's not intended to. And I like that.<br>It has made my work-time a blast and provided at least a 30% happiness boost. That's the real value.  </blockquote>
<div class="text has-size-6 has-text-">
	<p>During my communication design studies, a few friends and I started a small studio and built actual client websites in Kirby 3. A furniture store. An industrial supplier. The little shop around the corner. Whatever the brief was, Kirby could carry it.</p></div>
<div class="text has-size-6 has-text-">
	<p>Fast forward through a few years at an agency, and the same picture, just bigger. Mid-sized clients, with great ambitions. API backend for a Web app for a trade fair booth? Maintained through Kirby. Service Portals, Company pages, Blogs. Having worked with Typo3 and Drupal before, Kirby provided a faster development time, a closer connection to the design team and a better editor experience in the panel for sure. Going Headless with Kirby and KQL, I was mapping content blocks from the panel into a Nuxt frontend. A little change in the preview option and the editor experience stayed superb.</p></div>
<div class="text has-size-6 has-text-">
	<p>This is the part that does not sound impressive but is the actual quiet superpower: every month, a new client requirement lands on the table. With the german "Mittelstand" as customers, it was always something specific or weirdly shaped. And nevertheless the conversation nearly always ended with, "yeah, that will work fine with Kirby." A confidence, built up over years and not over hype cycles. Today Claudia and I run Gute Kombi, our own <a href="https://gutekombi.de/kirby-cms-agentur" target="_blank">brand and web studio</a>. Smaller team, same answer when a brief lands on the table.</p></div>
<div class="text has-size-6 has-text-">
	<p>And in 2026, the case for the underdog has only gotten stronger. Every week brings a new AI-powered framework promising to disrupt the disruptors. The hot library from a couple of years ago has either been abandoned, renamed, or absorbed into something else. Kirby is here. Still light, still PHP, still in the hands of the people who build with it.</p></div>
<div class="text has-size-6 has-text-">
	<p>With the beautiful projects built on Kirby I see every week, i feel like: This underdog is winning. We don't do 10x performance. We do not disrupt the industry. We just kind of... finish awesome projects. Outrageous, I know 😬</p></div>
<div class="text has-size-6 has-text-">
	<p>And now, my head will have Banks on repeat the whole day. Lalala as the underdog (Rah).</p></div>
]]>
				</content:encoded>
									<author>justus@moinfra.me (Justus Kraft)</author>
							</item>
					<item>
				<title>Adding a RSS Feed to Your Blog</title>
				<link>https://moinfra.me/posts/adding-a-rss-feed-to-your-blog</link>
				<guid>https://moinfra.me/posts/adding-a-rss-feed-to-your-blog</guid>
				<pubDate>Sun, 26 Apr 2026 00:00:00 +0200</pubDate>
				<description>
					<![CDATA[Kirby has a built-in feature called content representations that fits perfectly for such a task. How content representations work 	The idea is simple. Kirby maps URL extensions to template files. We already have a posts.php template that renders when someone visits /posts. If we create a file …]]>
				</description>
				<content:encoded>
					<![CDATA[<div class="text has-size-6 has-text-">
	<p>Kirby has a built-in feature called <strong>content representations</strong> that fits perfectly for such a task.</p></div>
<h2 class="title has-size-3 has-text-left">How content representations work</h2>
<div class="text has-size-6 has-text-">
	<p>The idea is simple. Kirby maps URL extensions to template files. We already have a <code>posts.php</code> template that renders when someone visits <code>/posts</code>. If we create a file called <code>posts.xml.php</code>, Kirby will automatically serve that when someone visits <code>/posts.xml</code>. This is perfect, since our RSS feed is just another representation of the same content – ha that name fits quite well i think :D</p> <p>We still have access to our <code>$page</code> object and all the content and methods of that page.</p> <p>You can also use this for JSON, or really any format you want. Worth checking out the <a href="https://getkirby.com/docs/guide/templates/content-representations" rel="noopener nofollow" target="_blank">Kirby docs on content representations</a> if you want to dive deeper.</p></div>
<h2 class="title has-size-3 has-text-left">A quick note on RSS</h2>
<div class="text has-size-6 has-text-">
	<p>Before we write the template, one thing: RSS is just XML. If you've never written XML, it's basically like HTML but stricter. Every tag must be closed, attribute values must be quoted, and special characters need to be escaped.</p> <p>For RSS specifically, there's a spec that defines a set of elements like <code>&lt;channel&gt;</code>, <code>&lt;item&gt;</code>, <code>&lt;title&gt;</code>, <code>&lt;description&gt;</code> and so on. The <a href="https://www.rssboard.org/rss-specification" rel="noopener nofollow" target="_blank">RSS 2.0 spec at rssboard.org</a> is a good reference, or just ask an LLM to generate it for you.</p></div>
<h2 class="title has-size-3 has-text-left">Building the template</h2>
<div class="text has-size-6 has-text-">
	<p>Let's create <code>site/templates/posts.xml.php</code>.</p> <p>RSS requires dates in RFC 2822 format and I'm using the PHP <code>intl</code> formatter,so we'll write a small helper script to create the timestamps.</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">function</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">rssDate</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">field</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #FFC799">string</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">  </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">field</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">toDate</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">EEE, dd MMM yyyy HH:mm:ss</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">.</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">.</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">field</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">toDate</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xx</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">)</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">}</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>Then we grab our posts, limited to the 20 most recent:</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">posts</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">page</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">children</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">published</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">sortBy</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">published</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">,</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">desc</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">limit</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">20</span><span class="token" style="color: #383A42;">)</span><span class="token">;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>Now the actual XML output.</p> <p>For escaping XML, we can use Kirby's built-in <code>Escape::xml()</code> method from the Toolkit (available as <code>esc($value, 'xml')</code>). It encodes special characters so they don't break the XML structure.</p> <p>We set the content type header and write the RSS channel metadata: title, description, link, language, and the build date from the most recent post.</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">php</span><span class="token"> </span><span class="token" style="color: #0184BC;;--phiki-dark-color: #FFC799">header</span><span class="token">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">Content-type: application/rss+xml; charset=utf-8</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token">;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">rss</span><span class="token"> </span><span class="token" style="color: #986801;">version</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">2.0</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #986801;">xmlns</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token" style="color: #986801;">content</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">http://purl.org/rss/1.0/modules/content/</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #986801;">xmlns</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token" style="color: #986801;">atom</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">http://www.w3.org/2005/Atom</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">channel</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">title</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="6"><span class="token">      </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">esc</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">site</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">title</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">.</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4"> - </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">.</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">page</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">title</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">title</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="8"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">description</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">esc</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">page</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">metaDescription</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">or</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">site</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">metaDescription</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">description</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="9"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">link</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">esc</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">page</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">url</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">link</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="10"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">atom</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token" style="color: #986801;">link</span><span class="token"> </span><span class="token" style="color: #986801;">href</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&lt;?= esc(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">page</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">url</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">() . &#039;.xml&#039;, &#039;xml&#039;) ?&gt;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #986801;">rel</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">self</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #986801;">type</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">application/rss+xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="11"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">language</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">kirby</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">language</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">code</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">language</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="12"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">lastBuildDate</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">rssDate</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">posts</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">first</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">published</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">lastBuildDate</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="13"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">php</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">foreach</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">posts</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">as</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="14"><span class="token">      </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">item</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="15"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">title</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">esc</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">title</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">title</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="16"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">link</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">esc</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">url</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">link</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="17"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">guid</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">esc</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">url</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">guid</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="18"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">pubDate</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">rssDate</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">published</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">pubDate</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="19"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">description</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="20"><span class="token">          </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">!</span><span class="token">[</span><span class="token" style="color: #986801;">CDATA</span><span class="token">[</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">main</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">toBlocks</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">excerpt</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">300</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">]]</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="21"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">description</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="22"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">content</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token" style="color: #986801;">encoded</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="23"><span class="token">          </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">!</span><span class="token">[</span><span class="token" style="color: #986801;">CDATA</span><span class="token">[</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">main</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">toBlocks</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">]]</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="24"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">content</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token" style="color: #986801;">encoded</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="25"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">php</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">if</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">author</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">post</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">author</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">toUser</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">)</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="26"><span class="token">          </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">author</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">esc</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">author</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">email</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">.</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4"> (</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">.</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">author</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">name</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">.</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">)</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">author</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="27"><span class="token">        </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">php</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">endif</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="28"><span class="token">      </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">item</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="29"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">php</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">endforeach</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="30"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">channel</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="31"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">/</span><span class="token" style="color: #986801;">rss</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>Let's walk through what's happening.</p><p>The &lt;channel&gt; element wraps everything and describes the feed itself. The &lt;atom:link&gt; with rel="self" is a self-referencing URL, which some feed readers expect. The &lt;lastBuildDate&gt; tells readers when the feed was last updated, and we just use the date of the most recent post for that.</p><p>For each post, we output an &lt;item&gt;. That's the main building block in RSS, each item is one entry in the feed.</p><p><strong>A few things worth noting:</strong></p></div>
<div class="text has-size-6">
	<ul><li>The &lt;guid&gt; is a globally unique identifier for the item. We just use the URL.</li><li>The &lt;description&gt; is a short excerpt. I'm using the first 300 characters of the rendered blocks.</li><li>The &lt;content:encoded&gt; contains the full content. Both description and content:encoded are wrapped in CDATA sections, so we can include HTML without having to escape every single tag.</li></ul></div><div class="text has-size-6 has-text-">
	<p>If your posts have an author field, the author block at the bottom adds it to the feed. If not, the if check just skips it.</p></div>
<h2 class="title has-size-2 has-text-left">Making the feed discoverable</h2>
<div class="text has-size-6 has-text-">
	<p>To make the feed discoverable, add an RSS autodiscovery tag in your <code>&lt;head&gt;</code>, in my case in the layout snippet:</p></div>

<pre class="phiki language-html one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="html"><code><span class="line" data-line="1"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">link</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">rel</span><span class="token" style="color: #383A42;">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">alternate</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">type</span><span class="token" style="color: #383A42;">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">application/rss+xml</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">title</span><span class="token" style="color: #383A42;">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">Posts</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">href</span><span class="token" style="color: #383A42;">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&lt;?= $page-&gt;url() . &#039;.xml&#039; ?&gt;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>This is what allows browsers and feed readers to automatically find your feed. And of course you can link to it visually in your posts template as well:</p></div>

<pre class="phiki language-html one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="html"><code><span class="line" data-line="1"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">a</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">href</span><span class="token" style="color: #383A42;">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&lt;?= $page-&gt;url() . &#039;.xml&#039; ?&gt;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">RSS Feed</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;/</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">a</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span></code></pre>]]>
				</content:encoded>
									<author>justus@moinfra.me (Justus Kraft)</author>
							</item>
					<item>
				<title>Global and Local Media Storage in Kirby CMS</title>
				<link>https://moinfra.me/posts/global-and-local-media-storage-in-kirby-cms</link>
				<guid>https://moinfra.me/posts/global-and-local-media-storage-in-kirby-cms</guid>
				<pubDate>Sun, 12 Apr 2026 00:00:00 +0200</pubDate>
				<description>
					<![CDATA[Kirby's approach to file storage is beautifully simple: every file lives inside its page folder. It's fast, it's clean, and it works great for page-specific content like article images. But when you have images that are used frequently on multiple pages, you end up uploading the same file over and …]]>
				</description>
				<content:encoded>
					<![CDATA[<div class="text has-size-6 has-text-">
	<p>Kirby's approach to file storage is beautifully simple: every file lives inside its page folder. It's fast, it's clean, and it works great for page-specific content like article images. But when you have images that are used frequently on multiple pages, you end up uploading the same file over and over.</p><p>A global media page can fix that, but going fully global has its own downsides. So how about a combination of both? That's exactly what we're looking at today.</p><p>This concept was shared by Sebastian from <a href="https://juno-hamburg.com" target="_blank">JUNO</a> during one of the first Kirby Meetups in Hamburg. Big shout out to them.</p></div>
<h2 class="title has-size-3 has-text-left">Setting Up the Global Media Page</h2>
<div class="text has-size-6 has-text-">
	<p>First, create a new folder in your <code>content</code> directory:</p></div>

<pre class="phiki language-text one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="text"><code><span class="line" data-line="1"><span class="token">content/globalmedia/globalmedia.txt
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>Then create a matching blueprint. The blueprint is straightforward, just one section for images:</p></div>

<pre class="phiki language-yml one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="yml"><code><span class="line" data-line="1"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">t</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">itle</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">G</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">lobal Media</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">o</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ptions</span><span class="token">:</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">   </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">e</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">xtends</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">p</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">ermissions/default</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">   </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">d</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">elete</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">false</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token">   </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">p</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">review</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">false</span><span class="token">
</span></span><span class="line" data-line="6"><span class="token">   </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">d</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">uplicate</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">false</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token">   </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">c</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">hangeStatus</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">false</span><span class="token">
</span></span><span class="line" data-line="8"><span class="token">   </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">c</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">hangeSlug</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">false</span><span class="token">
</span></span><span class="line" data-line="9"><span class="token">   </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">m</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ove</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">false</span><span class="token">
</span></span><span class="line" data-line="10"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">s</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">tatus</span><span class="token">:</span><span class="token">
</span></span><span class="line" data-line="11"><span class="token">  </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">u</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">nlisted</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">P</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">ublished</span><span class="token">
</span></span><span class="line" data-line="12"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">s</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ections</span><span class="token">:</span><span class="token">
</span></span><span class="line" data-line="13"><span class="token">  </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">i</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">mages</span><span class="token">:</span><span class="token">
</span></span><span class="line" data-line="14"><span class="token">    </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">t</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ype</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">f</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">iles</span><span class="token">
</span></span><span class="line" data-line="15"><span class="token">    </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">l</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ayout</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">t</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">able</span><span class="token">
</span></span><span class="line" data-line="16"><span class="token">    </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">s</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">earch</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">true</span><span class="token">
</span></span><span class="line" data-line="17"><span class="token">    </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">s</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ize</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">t</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">iny</span><span class="token">
</span></span><span class="line" data-line="18"><span class="token">    </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">t</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">emplate</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">i</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">mage</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>We lock down the options so editors can't accidentally duplicate or move the page. It's a utility page, not content.</p></div>
<h2 class="title has-size-3 has-text-left">Blocking the Frontend Route</h2>
<div class="text has-size-6 has-text-">
	<p>Since this page only stores media, it shouldn't be reachable on the frontend. Add a route to your <code>config.php</code>:</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token">  </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">routes</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">    </span><span class="token">[</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">      </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">pattern</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">/globalmedia</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token">      </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">method</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">GET</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line" data-line="6"><span class="token">      </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">action</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">function</span><span class="token"> </span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token">        </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="8"><span class="token">      </span><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="9"><span class="token">    </span><span class="token">]</span><span class="token">
</span></span><span class="line" data-line="10"><span class="token">  </span><span class="token">]</span><span class="token">
</span></span><span class="line" data-line="11"><span class="token">]</span><span class="token">;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>Now visiting <code>/globalmedia</code> returns a 404.</p></div>
<h2 class="title has-size-2 has-text-left">The Page Method: Local or Global?</h2>
<div class="text has-size-6 has-text-">
	<p>We need a way to decide, e.g. per template, whether file uploads should go to the page itself or to the global media page.</p> <p>Create a plugin (e.g. <code>site/plugins/project-helper</code>) and add a page method:</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #C18401;;--phiki-dark-color: #FFC799">Kirby</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">::</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">plugin</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">project/helper</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">,</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">[</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="2"><span class="token" style="color: #383A42;">  </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">pageMethods</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">[</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="3"><span class="token" style="color: #383A42;">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">mediaPage</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">function</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">{</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="4"><span class="token" style="color: #383A42;">      </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">mediaPage</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">page</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">globalmedia</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;">;</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="5"><span class="token" style="color: #383A42;">      </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">if</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">!</span><span class="token" style="color: #C18401;;--phiki-dark-color: #FFC799">V</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">::</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">in</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">intendedTemplate</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;">,</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">[</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">note</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">]</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">mediaPage</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">??</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">;</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="6"><span class="token" style="color: #383A42;">      </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">;</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="7"><span class="token" style="color: #383A42;">    </span><span class="token" style="color: #383A42;">}</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="8"><span class="token" style="color: #383A42;">  </span><span class="token" style="color: #383A42;">]</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="9"><span class="token" style="color: #383A42;">]</span><span class="token" style="color: #383A42;">)</span><span class="token">;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>The idea: templates listed in the array, <code>note</code> in this case, keep their files locally. Everything else uses the global media page. So a note stores its images in its own folder, but a page like "About" pulls from the shared pool.</p></div>
<h2 class="title has-size-3 has-text-left">Wiring Up File Fields</h2>
<div class="text has-size-6 has-text-">
	<p>Now update your file fields to use this method. For example, a <code>cover</code> field from the starterkit:</p></div>

<pre class="phiki language-yml one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="yml"><code><span class="line" data-line="1"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">c</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">over</span><span class="token">:</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token">  </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">t</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ype</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">f</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">iles</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">  </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">m</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ultiple</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">false</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">  </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">q</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">uery</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">p</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">age.mediaPage.images.template(&#039;image&#039;)</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token">  </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">u</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">ploads</span><span class="token">:</span><span class="token">
</span></span><span class="line" data-line="6"><span class="token">    </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">p</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">arent</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">p</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">age.mediaPage</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token">    </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">t</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFC799">emplate</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">i</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">mage</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>The <code>uploads.parent</code> tells Kirby where to store new uploads, and the <code>query</code> tells the field where to look for existing files. Both point to <code>page.mediaPage</code>, which returns either the page itself or the global media page.</p> <p>Do the same for image blocks or any other file fields where this applies.</p></div>
<h2 class="title has-size-3 has-text-left">Quick Access in the Panel</h2>
<div class="text has-size-6 has-text-">
	<p>For convenience, add the global media page to your panel sidebar. I'm using the <a href="https://moinfra.me/docs/moinframe-panel-menu" target="_blank">Kirby Panel Menu</a> plugin for this, which generates a sidebar menu.</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">panel</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token">[</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">  </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">menu</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">fn</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">kirby</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token">=&gt;</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">panelMenu</span><span class="token">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">kirby</span><span class="token">)</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">site</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">page</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">Media</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">,</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">globalmedia</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">,</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">[</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">icon</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">images</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">]</span><span class="token" style="color: #383A42;">)</span><span class="token">
</span></span><span class="line" data-line="6"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">area</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">users</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">)</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">area</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">system</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">)</span><span class="token">
</span></span><span class="line" data-line="8"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">toArray</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token">
</span></span><span class="line" data-line="9"><span class="token">  </span><span class="token">]</span><span class="token">
</span></span><span class="line" data-line="10"><span class="token">]</span><span class="token">;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>With everything in place, each template gets the storage strategy that makes sense for it.</p> <p>The beauty of this approach is that you define the rules once in the plugin, and every file field across your site respects them automatically.</p></div>
]]>
				</content:encoded>
									<author>justus@moinfra.me (Justus Kraft)</author>
							</item>
					<item>
				<title>How to create simple methods to render snippets</title>
				<link>https://moinfra.me/posts/how-to-create-simple-methods-to-render-snippets</link>
				<guid>https://moinfra.me/posts/how-to-create-simple-methods-to-render-snippets</guid>
				<pubDate>Sun, 05 Apr 2026 00:00:00 +0200</pubDate>
				<description>
					<![CDATA[If you work with Kirby a lot, you probably have some snippets you use all the time. Not a big deal in itself, but the default snippet syntax can get pretty verbose over time, especially when you use the same snippet in many places.Let's see how a simple helper method can make your snippet calls …]]>
				</description>
				<content:encoded>
					<![CDATA[<div class="text has-size-6 has-text-">
	<p>If you work with Kirby a lot, you probably have some snippets you use all the time. Not a big deal in itself, but the <a href="https://getkirby.com/docs/guide/templates/snippets" target="_blank">default snippet syntax </a>can get pretty verbose over time, especially when you use the same snippet in many places.</p><p>Let's see how a simple helper method can make your snippet calls much shorter and more readable.</p></div>
<h2 class="title has-size-3 has-text-left">Default snippet syntax</h2>
<div class="text has-size-6 has-text-left">
	<p>In my projects, I often use an icon snippet that renders an SVG from a sprite. It accepts two parameters, $name and $size, and looks like this:</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">php</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token" style="color: #A626A4;;--phiki-dark-color: #FFC799">use</span><span class="token" style="--phiki-dark-color: #FFC799"> </span><span class="token" style="--phiki-dark-color: #FFC799">Kirby</span><span class="token" style="--phiki-dark-color: #A0A0A0">\</span><span class="token" style="--phiki-dark-color: #FFC799">Toolkit</span><span class="token" style="--phiki-dark-color: #A0A0A0">\</span><span class="token" style="color: #C18401;;--phiki-dark-color: #FFC799">Str</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">
</span></span><span class="line" data-line="4"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">name</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">name</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">??</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">size</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">size</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">??</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">1em</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="6"><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">sprite</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">asset</span><span class="token">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">icons.svg</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="8"><span class="token">
</span></span><span class="line" data-line="9"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">i</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">class</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">i</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #986801;">style</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">--size: &lt;?= </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">size</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">?&gt;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token"> </span><span class="token" style="color: #986801;">data</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-</span><span class="token" style="color: #986801;">icon</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&lt;?= </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">name</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">?&gt;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="10"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #986801;">svg</span><span class="token"> </span><span class="token" style="color: #986801;">aria</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-</span><span class="token" style="color: #986801;">hidden</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span><span class="line" data-line="11"><span class="token">    </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #FFC799">use</span><span class="token" style="--phiki-dark-color: #FFC799"> </span><span class="token" style="color: #C18401;;--phiki-dark-color: #FFC799">xlink</span><span class="token" style="--phiki-dark-color: #FFC799">:</span><span class="token" style="color: #C18401;;--phiki-dark-color: #FFC799">href</span><span class="token" style="--phiki-dark-color: #FFC799">=&quot;&lt;?= $</span><span class="token" style="color: #C18401;;--phiki-dark-color: #FFC799">sprite</span><span class="token" style="--phiki-dark-color: #FFC799">-&gt;</span><span class="token" style="color: #C18401;;--phiki-dark-color: #FFC799">url</span><span class="token" style="--phiki-dark-color: #FFC799">() </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">v</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">sprite</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">-&gt;</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">mediaHash</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #A0A1A7;;--phiki-dark-color: #8b8b8b94">#</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #8b8b8b94">symbol-&lt;?= $name </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4"> /&gt;
</span></span><span class="line" data-line="12"><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">  &lt;/svg&gt;
</span></span><span class="line" data-line="13"><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&lt;/i&gt;
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>Normally, you'd call the snippet like this:</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #986801;">php</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">snippet</span><span class="token">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">icon</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">name</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">phone</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">size</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">1.25em</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">]</span><span class="token">)</span><span class="token">;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-left">
	<p>Works perfectly fine, but let's be honest, for a tiny icon inside a simple HTML structure, that's a bit cumbersome. Wouldn't it be nice to write it like this?</p></div>

<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&lt;</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">icon</span><span class="token">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">phone</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">?</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">&gt;</span><span class="token">
</span></span></code></pre><h2 class="title has-size-3 has-text-left">The solution: A small plugin</h2>
<div class="text has-size-6 has-text-">
	<p>Here is how you do it:</p></div>
<div class="text has-size-6">
	<ol><li>Create a new folder in <code>site/plugins</code> and name it something like <code>project-helper</code>. I like differentiating internal plugins from externally installed ones by name, but you can call the folder whatever you want of course.</li><li>In the plugin's <code>index.php</code>, add the new method:</li></ol></div>
<pre class="phiki language-php one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="php"><code><span class="line" data-line="1"><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">function</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">icon</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #FFC799">string</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">name</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #FFC799">string</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">size</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">1em</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #383A42;">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token">	</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token"> </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">snippet</span><span class="token">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">icon</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">name</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">name</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">size</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&#039;</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=&gt;</span><span class="token"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">size</span><span class="token">]</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #986801;">true</span><span class="token">)</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">}</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>The method is basically just a slim wrapper around Kirby's snippet() method. It accepts the same parameters and returns the rendered snippet. The key detail: Passing true as the third argument makes the snippet return the HTML as a string instead of echoing it directly.</p></div>
<div class="text has-size-6 has-text-left">
	<p>This principle applies to any snippet you use frequently of course. Especially for small, recurring building blocks like icons, buttons, or badges, it saves quite a bit of typing and makes your templates noticeably cleaner.</p></div>
]]>
				</content:encoded>
									<author>justus@moinfra.me (Justus Kraft)</author>
							</item>
					<item>
				<title>Extend Panel Components Without Overwriting Them</title>
				<link>https://moinfra.me/posts/extend-panel-components-without-overwriting-them</link>
				<guid>https://moinfra.me/posts/extend-panel-components-without-overwriting-them</guid>
				<pubDate>Sun, 29 Mar 2026 00:00:00 +0100</pubDate>
				<description>
					<![CDATA[Ever wanted to add a small feature to a built-in panel component but hesitated because you didn't want to lose future Kirby updates? I've been there. Today I want to show you a clean way to extend panel components without overwriting them entirely. The Problem 	Let's say you have a heading block …]]>
				</description>
				<content:encoded>
					<![CDATA[<div class="text has-size-6 has-text-">
	<p>Ever wanted to add a small feature to a built-in panel component but hesitated because you didn't want to lose future Kirby updates? I've been there. Today I want to show you a clean way to extend panel components without overwriting them entirely.</p></div>
<h2 class="title has-size-3 has-text-left">The Problem</h2>
<div class="text has-size-6 has-text-">
	<p>Let's say you have a heading block and you've added two custom fields: a style field (letting editors choose visual styles independent of the semantic level) and an text alignment field. Both work perfectly fine in the block drawer.</p><p>But here's the thing: the preview in the blocks field doesn't reflect those choices. The editor has no idea if a heading is centered or styled differently until they open the block again. That's not great UX.</p><p>The obvious solution would be to overwrite the k-block-type-heading component. Copy the whole thing, modify it, done. But then you're on the hook for maintaining that code whenever Kirby updates its panel. Not ideal.</p></div>
<h2 class="title has-size-3 has-text-left">A Better Approach: Extend, Don't Overwrite</h2>
<div class="text has-size-6 has-text-">
	<p>Instead of replacing the component, we can extend it. Vue (and Kirby's panel plugin system) makes this surprisingly straightforward.</p> <p>I've set up a minimal plugin with just two files:</p></div>

<pre class="phiki language-text one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="text"><code><span class="line" data-line="1"><span class="token">plugins/panel-extend/
</span></span><span class="line" data-line="2"><span class="token">├── index.js
</span></span><span class="line" data-line="3"><span class="token">└── index.css
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>Both files get autoloaded by the panel. No extra registration needed.</p></div>
<h3 class="title has-size-3 has-text-left">The JavaScript</h3>
<div class="text has-size-6 has-text-">
	<p>In <code>index.js</code>, we define the plugin and extend the existing component:</p></div>

<pre class="phiki language-js one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="js"><code><span class="line" data-line="1"><span class="token" style="color: #383A42;;--phiki-dark-color: #FFF">window</span><span class="token">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">panel</span><span class="token">.</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">plugin</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">your-name/panel-extend</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token">  </span><span class="token" style="color: #E45649;">components</span><span class="token" style="color: #0184BC;">:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">    </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">k-block-type-heading</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #0184BC;">:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">      </span><span class="token" style="color: #E45649;">extends</span><span class="token" style="color: #0184BC;">:</span><span class="token"> </span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">k-block-type-heading</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token">,</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token">      
</span></span><span class="line" data-line="6"><span class="token">      </span><span class="token" style="color: #E45649;">methods</span><span class="token" style="color: #0184BC;">:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token" style="color: #383A42;">        </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">updateDataAttributes</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">{</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="8"><span class="token" style="color: #383A42;">          </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">const</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">{</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFF">alignment</span><span class="token" style="color: #383A42;">,</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFF">style</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">}</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">content</span><span class="token" style="color: #383A42;">;</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="9"><span class="token" style="color: #383A42;">          </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">if</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">!</span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$el</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">return</span><span class="token" style="color: #383A42;">;</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="10"><span class="token" style="color: #383A42;">          </span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$el</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">dataset</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">alignment</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFF">alignment</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="11"><span class="token" style="color: #383A42;">          </span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">$el</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">dataset</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">style</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFF">style</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="12"><span class="token" style="color: #383A42;">        </span><span class="token" style="color: #383A42;">}</span><span class="token">
</span></span><span class="line" data-line="13"><span class="token">      </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line" data-line="14"><span class="token">      
</span></span><span class="line" data-line="15"><span class="token">      </span><span class="token" style="color: #E45649;">watch</span><span class="token" style="color: #0184BC;">:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="16"><span class="token">        </span><span class="token" style="color: #E45649;">content</span><span class="token" style="color: #0184BC;">:</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="17"><span class="token" style="color: #383A42;">          </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">handler</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">{</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="18"><span class="token" style="color: #383A42;">            </span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">updateDataAttributes</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;">;</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="19"><span class="token" style="color: #383A42;">          </span><span class="token" style="color: #383A42;">}</span><span class="token">,</span><span class="token">
</span></span><span class="line" data-line="20"><span class="token">          </span><span class="token" style="color: #E45649;">deep</span><span class="token" style="color: #0184BC;">:</span><span class="token"> </span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">true</span><span class="token">
</span></span><span class="line" data-line="21"><span class="token">        </span><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="22"><span class="token">      </span><span class="token">}</span><span class="token">,</span><span class="token">
</span></span><span class="line" data-line="23"><span class="token">      
</span></span><span class="line" data-line="24"><span class="token" style="color: #383A42;">      </span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">mounted</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;"> </span><span class="token" style="color: #383A42;">{</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="25"><span class="token" style="color: #383A42;">        </span><span class="token" style="color: #E45649;;--phiki-dark-color: #A0A0A0">this</span><span class="token" style="color: #383A42;">.</span><span class="token" style="color: #4078F2;;--phiki-dark-color: #FFC799">updateDataAttributes</span><span class="token" style="color: #383A42;">(</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;">;</span><span class="token" style="color: #383A42;">
</span></span><span class="line" data-line="26"><span class="token" style="color: #383A42;">      </span><span class="token" style="color: #383A42;">}</span><span class="token">
</span></span><span class="line" data-line="27"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="28"><span class="token">  </span><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="29"><span class="token">}</span><span class="token" style="color: #383A42;">)</span><span class="token" style="color: #383A42;">;</span><span class="token">
</span></span></code></pre><div class="text has-size-6 has-text-">
	<p>What's happening here:</p></div>
<div class="text has-size-6">
	<ol><li>We use <code>extends: &quot;k-block-type-heading&quot;</code> to inherit all the existing component code.</li><li>We add a method that reads <code>style</code> and <code>alignment</code> from the block content and sets them as data attributes on the element.</li><li>We watch for content changes and update the attributes when the editor makes selections.</li><li>On mount, we set the initial values.</li></ol></div><div class="text has-size-6 has-text-">
	<p>That's it for the JS. We're not touching any of the original rendering logic, just adding data attributes that CSS can hook into.</p></div>
<h3 class="title has-size-3 has-text-left">The CSS</h3>
<div class="text has-size-6 has-text-">
	<p>In <code>index.css</code>, we use those data attributes to style the preview:</p></div>

<pre class="phiki language-css one-light phiki-themes vesper" style="background-color: #FAFAFA;color: #383A42;;--phiki-dark-background-color: #101010;--phiki-dark-color: #FFF" data-language="css"><code><span class="line" data-line="1"><span class="token" style="color: #A0A1A7;;--phiki-dark-color: #8b8b8b94">/*</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #8b8b8b94"> Styles </span><span class="token" style="color: #A0A1A7;;--phiki-dark-color: #8b8b8b94">*/</span><span class="token">
</span></span><span class="line" data-line="2"><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">.</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">k-block-type-heading-input</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">[</span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">data-style</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">h1</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">]</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="3"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">font-size</span><span class="token" style="--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #0184BC;;--phiki-dark-color: #FFC799">var</span><span class="token" style="--phiki-dark-color: #A0A0A0">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">--text-3xl</span><span class="token" style="--phiki-dark-color: #A0A0A0">)</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="4"><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="5"><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">.</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">k-block-type-heading-input</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">[</span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">data-style</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">h2</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">]</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="6"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">font-size</span><span class="token" style="--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #0184BC;;--phiki-dark-color: #FFC799">var</span><span class="token" style="--phiki-dark-color: #A0A0A0">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">--text-2xl</span><span class="token" style="--phiki-dark-color: #A0A0A0">)</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="7"><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="8"><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">.</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">k-block-type-heading-input</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">[</span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">data-style</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">h3</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">]</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="9"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">font-size</span><span class="token" style="--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #0184BC;;--phiki-dark-color: #FFC799">var</span><span class="token" style="--phiki-dark-color: #A0A0A0">(</span><span class="token" style="color: #E45649;;--phiki-dark-color: #FFF">--text-xl</span><span class="token" style="--phiki-dark-color: #A0A0A0">)</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="10"><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="11"><span class="token" style="color: #A0A1A7;;--phiki-dark-color: #8b8b8b94">/*</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #8b8b8b94"> ... h4, h5, h6 </span><span class="token" style="color: #A0A1A7;;--phiki-dark-color: #8b8b8b94">*/</span><span class="token">
</span></span><span class="line" data-line="12"><span class="token">
</span></span><span class="line" data-line="13"><span class="token" style="color: #A0A1A7;;--phiki-dark-color: #8b8b8b94">/*</span><span class="token" style="color: #A0A1A7;font-style: italic;;--phiki-dark-color: #8b8b8b94"> Alignment </span><span class="token" style="color: #A0A1A7;;--phiki-dark-color: #8b8b8b94">*/</span><span class="token">
</span></span><span class="line" data-line="14"><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">.</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">k-block-type-heading-input</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">[</span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">data-alignment</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">left</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">]</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="15"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">text-align</span><span class="token" style="--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">left</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="16"><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="17"><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">.</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">k-block-type-heading-input</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">[</span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">data-alignment</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">center</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">]</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="18"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">text-align</span><span class="token" style="--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">center</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="19"><span class="token">}</span><span class="token">
</span></span><span class="line" data-line="20"><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">.</span><span class="token" style="color: #986801;;--phiki-dark-color: #FFC799">k-block-type-heading-input</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">[</span><span class="token" style="color: #986801;;--phiki-dark-color: #A0A0A0">data-alignment</span><span class="token" style="color: #383A42;;--phiki-dark-color: #A0A0A0">=</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">right</span><span class="token" style="color: #50A14F;;--phiki-dark-color: #99FFE4">&quot;</span><span class="token" style="color: #A626A4;;--phiki-dark-color: #A0A0A0">]</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line" data-line="21"><span class="token">  </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">text-align</span><span class="token" style="--phiki-dark-color: #A0A0A0">:</span><span class="token"> </span><span class="token" style="color: #383A42;;--phiki-dark-color: #FFC799">right</span><span class="token">;</span><span class="token">
</span></span><span class="line" data-line="22"><span class="token">}</span><span class="token">
</span></span></code></pre><h2 class="title has-size-3 has-text-left">The Result</h2>
<div class="text has-size-6 has-text-">
	<p>Now when an editor changes the style or alignment in the block settings, the preview updates instantly. They can see that a heading is centered or styled as an H1 without having to open the drawer.</p> <p>One thing to keep in mind: these are panel-only styles. Your frontend snippet still needs to handle the actual output. But for the editing experience, this makes a real difference.</p></div>
<h2 class="title has-size-3 has-text-left">Why This Matters</h2>
<div class="text has-size-6 has-text-">
	<p>Small touches like this help editors understand what they're building. A live preview that reflects their choices reduces friction and makes the panel feel more polished.</p><p>And the best part? When Kirby releases an update with improvements to the heading block component, you'll get those for free. Your extension just adds to the existing code, it doesn't replace it.</p><p>Give it a try. Extend what you need, keep what works.</p></div>
]]>
				</content:encoded>
									<author>justus@moinfra.me (Justus Kraft)</author>
							</item>
					<item>
				<title>Welcome to the blog</title>
				<link>https://moinfra.me/posts/welcome-to-the-blog</link>
				<guid>https://moinfra.me/posts/welcome-to-the-blog</guid>
				<pubDate>Sat, 28 Mar 2026 00:00:00 +0100</pubDate>
				<description>
					<![CDATA[Helloo world! During the last Kirby Meetup in Bremen, René, Jonas and I were talking about the moinframe channel and a valid idea came up: Why not have a blog that accompanies the channel. For one, it would help persist some of the knowledge. Two, it makes things easier to find through search …]]>
				</description>
				<content:encoded>
					<![CDATA[<div class="text has-size-6 has-text-left">
	<p>Helloo world! </p><p>During the last Kirby Meetup in Bremen, <a href="https://rene-henrich.de" target="_blank">René</a>, <a href="https://jonasrebmann.de" target="_blank">Jonas</a> and I were talking about the moinframe channel and a valid idea came up: Why not have a blog that accompanies the channel. </p><p>For one, it would help persist some of the knowledge. Two, it makes things easier to find through search engines. </p><p>And there's a third reason I've been thinking about for a while:<strong> </strong>code examples. In most videos I'm showing off something code related and being able to just copy, paste and modify yourself is a huge win.</p><p>At first I was a bit hesitant. I know I need to keep control over how much time I dedicate to the YouTube channel to keep it going while still having enough headspace for my own business, and, well, free time: what even is that?</p><p>So here's the plan: Try this out, have posts related to the videos, and see where this goes.</p><p>Hope you're coming along!</p></div>
]]>
				</content:encoded>
									<author>justus@moinfra.me (Justus Kraft)</author>
							</item>
			</channel>
</rss>
