github getkirby/kirby 5.5.0

6 hours ago

🎉 Features

Local development licenses

A Kirby site can now be activated as development site when you confirm to comply with the license terms for free development licenses. When the site is not set up locally, Kirby will regularly check that your development site is not publicly accessible. #7832

Screenshot 2026-07-01 at 16 02 33

Frontmatter Data Handler

New Frontmatter Data handler, which can be used to import or export frontmatter into Kirby. #8019

Decoding

use Kirby\Data\Frontmatter;

$md = <<<MD
---
title: My new article
date: '2026-03-12'
---
# Hello world

This is my brand new article written in **Frontmatter/Markdown**
MD;

$result = Frontmatter::decode($md);

// [
//  'title' => 'My new article',
//  'date' => '2026-03-12',
//  'text' => '# Hello world ...'
// ]

Encoding

use Kirby\Data\Frontmatter;

$result = Frontmatter::encode([
  'title' => 'My new article',
  'date' => '2026-03-12',
  'text' => '# Hello world …'
]);

// ---
// title: My new article
// date: 2026-03-12
// ---
// # Hello world …

New translations

  • Japanese (thanks to Kosuke Okahara)
  • Ukranian

✨ Enhancements

  • SmartyPants is directly using UTF-8 characters instead of HTML entities
  • A page/site/user/file will now automatically be unlocked, as soon as the editor leaves the view or closes the tab/window. This will make sure that content-editing is not unnecessarily blocked for other editors. #7975
    • New Kirby\Content\Version::unlock() method
    • New panel.content.unlock() method
    • New /api/(:all)/changes/unlock route
  • License dialog: Show registered domain and link to license terms #7832
  • You can now use this.$helper.string.sanitizeHTML() in the Panel to create a clean HTML string with configurable marks and nodes. By default, the sanitizer will only keep inline marks (bold, code, italic, link, strike, sub, sup, underline) #7922
    this.$helper.string.sanitizeHTML('<p><marquee><strong onclick="alert(\'boo\')">Foo</strong></marquee></p>')
    // returns: <strong>Foo</strong>
    To set custom writer marks and nodes, you can pass an options object:
    this.$helper.string.sanitizeHTML(unsanitizedHTML, {
      marks: ["bold"],
      nodes: ["doc", "praagraph", "text")]
    });
  • It's now possible to define any extension directly in your config, to be able to set site-specific extensions without creating a helper plugin. #8005
    // /site/config/config.php
    
    return [
      'extensions' => [
        'pageModels' => [
          // ...
        ],
        'blueprints' => [
          // ...
        ]
      ]
    ];
  • Link field: reduced the amount of backend request fired directly when mounted (thx @tobimori) #8072
  • Added some missing common/modern extensions to Kirby\Filesystem\F::$types and Kirby\Filesystem\Mime::$types. #8134
  • New Kirby\Toolkit\A::flip() method #8132
  • Increased length of randomly generated chunk IDs for chunked uploads to reduce risk of filename collisions #8182
  • New Kirby\Filesystem\F::update($file, $callback) method that reads and updates a file under lock #8187
  • Improved error handling for block snippet errors rendered via Kirby\Cms\Block::toHtml() by logging suppressed errors and escalating exceptions in debug mode #8085.
  • Added a translatable default placeholder for the tags field input #6114

🏎️ Performance

  • Improved performance of several system methods:
    • Kirby\Filesystem\Dir::size() #8131
    • Kirby\Filesystem\Mime::fromSvg() #8130
    • Kirby\Filesystem\Mime::toExtension() and Kirby\Filesystem\Mime::toExtensions() #8133
    • Kirby\Toolkit\Controller #8143
    • Kirby\Toolkit\Html::attr() and Kirby|Toolkit\Xml::encode() #8144
    • Kirby\Toolkit\Str::similarity(), Kirby\Toolkit\Str::startsWith(), Kirby\Toolkit\Str::endsWith(), Kirby\Toolkit\Str::encode(), Kirby\Toolkit\Str::ascii() #8138 #8147 #8145 #8158
    • Excluded keys lookup set in Kirby\Toolkit\A::without() #8146

🐛 Bug fixes

  • Structure field previews: fields with HTML content (e.g. list, writer) do not expand the table with all their content anymore #7918
  • Fixed URL validation for URLs with multiple hyphens #7942
  • Redis cache driver: Fixed flushing all databases even when using a prefix. Now only the Reds database for the cache with its prefix gets flushed. #8148
  • Fixed minWords/maxWords validators for non-single whitespace #8141
  • Handle Dir::remove() with atomic rename #6266
  • panel.request.body(null) does not send "null" to the backend as the request body anymore #8016
  • Unset request headers aren't sent as "false" to the backend anymore but instead omitted from the request. #8016
  • Fixed handling of partial step config arrays in Kirby\Toolkit\Date
  • Kirby\Toolkit\LayzValue: fixed passing variadic arguments #8139
  • Kirby\Toolkit\A::implode(): preserve falsy values when imploding array #8140
  • Fixed fractional support for Kirby\Toolkit|Str::toBytes() #8159
  • Blocks field: Fixed batch delete #8206
  • Panel system view: The warning for the default cookie key is no longer displayed if a custom cookie key was set via the cookie.key option
  • Panel: Fixed failing to load when a stricter Content-Security-Policy with nonce-based script-src is used. #8208
  • I18n::template(): Prevent TypeError when $replace is null #8199
  • Kirby queries: Fixed tokenizer position desync on multibyte characters (@thx @LaurentTacco) #8203
  • Fixed a content lock deadlock in multilingual setups where saving a secondary language while another user holds the lock on the primary language would cause both users to see the page as locked by the other. #8099
  • Fixed file sorting when a secondary language is active #8212
  • Fixed Cmd/Ctrl+S in textarea toolbar dialogs inserting [object Object] instead of the formatted link/email text. #7934
  • Disabled unselected model picker options once the field’s max limit is reached #8232
  • Localize license hub link #8239

☠️ Deprecated

  • Using arbitrary custom permissions without registering them first via the permissions extension has been deprecated. Those will be ignored in a future release, so make sure to define your custom permissions via the permissions extension. #8070
  • Kirby\Text\KirbyTag::option() and Kirby\Text\KirbyTag::$options: Use $tag->kirby()->option() instead. #8196
  • Kirby\Text\KirbyTags::parse(): $options parameter. Use new $debug parameter instead. #8196

♻️ Refactored

  • New Kirby\Cms\LicenseStatus::Acknowledged and Kirby\Cms\LicenseType::Free cases #7832
  • $helper.string.hasEmoji(): simplified regular expression #7966
  • Started refactoring some of our JavaScript code as TypeScript for increased type-safety #7973
  • New RedirectError error class with support in panel.error() #8016
  • Refactored Permissions (thanks to @lukaskleinschmidt) #8004
    • Renamed Permissions::$actions property to $defaults; added separate protected array $actions populated by the constructor
    • Replaced 6 old methods (Permissions::setAll, Permissions::setCategory, Permissions::setCategories, Permissions::setAction, Permissions::hasAction, Permissions::hasCategory) with 4 cleaner ones: Permissions::normalize(), Permissions::expand(), Permissions::get(), Permissions::has()
    • Permissions::normalize() and Permissions::expand() handle all four input shapes: null, bool, ['cat' => bool], ['cat' => ['action' => bool]], including wildcard at both levels.
    • Permissions::for() now deprecates $category = null via Helpers::deprecated() and throws LogicException if a stored value is somehow not a bool
    • Slightly refactored the Blueprint class: array_fill_keys(array_keys($defaults), false) instead of array_map(fn () => false, $defaults).
  • Ensure not wrapping <div> tags with <span> tags in <k-input> #8018
  • New Kirby\Template\Snippet::hasSlots() method #8178
  • Guard Slots in Snippets from being double-opened #8179
  • New $debug parameter in Kirby\Text\KirbyTags::parse() #8196
  • Clarify Html::rel() use #8142

🚨 Breaking changes

  • Kirby\Cms\Block::toHtml() now throws block snippet exceptions in debug mode instead of returning an inline Block error message. While this is technically a breaking change, we see this as a debugging enhancement which can clearly go into a minor release without negative impact for real-world projects.

🧹 Housekeeping

  • Extended our contributing guidelines #7949
  • Attaching files for local Lab to each release #7951
  • Use cpx for pinned composer dependencies shared between local dev and CI
  • Replace jsdom with happy-dom for frontend unit tests #7971
  • New Unit tests for the Permissions class #8004
  • New Unit test for the new option normalization in the Blueprint class #8004
  • Upgraded Parsedown library #8213

Don't miss a new kirby release

NewReleases is sending notifications on new releases.