New Unique ID system
For everlasting relationships
Reliability built-in
With Kirby’s new UUID system, we are building reliable, unique IDs right into the core. Not just for pages, also for files and users. Unique IDs are stored in your content files and efficiently cached on demand for fast lookup.
Permalinks
Pages and files now have their own permalink that will never change – even if you rename the slug or a filename. The permalinks will automatically redirect to the current URL of the page or file. They are also great shortlinks.
Updated picker fields
All our picker fields now store UUIDs by default. Related pages and files can now safely be renamed without breaking relationships.
New update checks
Keep your installation healthy
Always up to date
Our new update check in the enhanced system view makes it easy to stay informed about the version and security status of Kirby and your installed plugins.
While feature updates are not always needed for finished sites, keeping an eye on security issues and important security messages is really important to keep your sites secure and healthy.
The new update check brings this information and more right into the Panel so you can get a quick overview of the status of your site.
Fine-tuning the behavior is really simple:
PHP 7.4+ PHP 8+
Use the potential of a modern PHP environment
There’s no time to dwell in the past
Kirby has already supported PHP 8.0 and 8.1 right after their release. PHP 8 not only brings an incredible performance boost but also language features that really move Kirby forward.
Kirby 3.8 builds exclusively on PHP 8+. With the end-of-life of PHP 7.4 in November and wide-spread hosting support for PHP 8, we don't see any reason to stay with an outdated version if the future is so bright.
New object field
More power for your data
Objectively awesome
The new object field allows to create data objects. This is super handy for more complex settings, isolated entities or nested data.
In your blueprints
The object field definition is very similar to a structure field. You can define any set of fields for the object with the fields
option.
In your templates
The result is stored as YAML in the content file and can be used in your templates with the new $field->toObject()
method.
Kirby CLI
Supercharge your workflow
Coming to a terminal near you
The revival of our command line interface is here and it’s better than ever before. Install Kirby and its kits in seconds, make blueprints, templates, controllers and more or extend the CLI with your own commands. Managing your Kirby installations has never been easier.
Better gallery block
Artistic control for your images
Better settings
Better preview
Changelog
Features
Panel
Core
- Unique IDs for pages, files, users and site #4612
- Permanent URLs for pages and files with UUIDs #4612
- New
$users->files()
method (returning a collection of all files of the users) #4499 - Support for a newÂ
site/config/env.php
 file for options that are specific to a deployment: It can override all options fromÂconfig.php
 and from the config files specific to hostname and server IP address. It can also override theÂurl
 option and control which hostname-specific files will be loaded. #4580 - New
$cache->getOrSet($key, $callback, $minutes)
 method: Retrieves the value from cache if possible, if not via callback function and adds it to the cache #4627 - New
$cache->enabled()
method to check if the cache is ready to store values #4661 - New option to disable the output from
$kirby->render()
via$_ENV['KIRBY_RENDER'] = false
- New
commands
root which is set tosite/commands
by default - New ability to define CLI commands in Kirby plugins:
Enhancements
Panel
- Better gallery block features new ratio, crop and caption fields and displays images according to selected ratio #4652.
- Better error messages for blocks and layout fields #Nolt313
- The error dialog now displays multiple error lines per field #4629
- System view: Empty plugin table cells display "–" #4444
- When a login challenge has expired, the user is redirected to the login page. #4087
- Added new
onFormInput
handler of the structure field on form submit event #4616 - Each report in a
k-stats
widget can now define adialog
prop with the name of a dialog to be opened when the report is clicked. #4658 - Fiber dialogs: the submit button is now disabled while processing a submit request to prevent sending multiple requests at once accidentally #4413
- Table rows use the same outline styling when dragged as cards and lists #4682
- Easily translate options via an i18n key #3955:
Core
- The
$field->replace()
,$modelWithContent->toString()
,$modelWithContent->toSafeString()
andStr::safeTemplate()
methods now support the fallback valuenull
(which leaves invalid tokens in the output string). #4671
Bug fixes
Panel
- Tags field: Separates tags on blur correctly #4638
- Tags field: Doesn't lose current input when hitting Cmd+S #4590
- Various escaping issues for fields with options #4043 #4229
- Picker fields: Fixed styling for disabled/non-translatable state #4306
- Structure field:
columns
options now rightly overrule implied options from the field #4514 - URL field preview is properly truncated with an ellipsis when it is too long #4677
- Users view: The role filter is not shown anymore if there is only one role available #4673
- The template of the home page can be changed now #4571
- Items are properly highlighted while being dragged #4648
- The table layout heading alignment is now working properly #4630
- Uploaded XML files are no longer blocked because they contain links to external domains #4553
- The Panel now suppresses error dialog when redirecting to logout #4614
- We brought back the default slot for
k-items
#4635 - When the structure field is used with limit, the index number now shows correctly #4695
- The Panel now uses the correct favicon in dark mode #4691
- Reduced impact of frequent lock requests on the server load #4741
Core
- Calling aÂ
$file
 method inside a customÂfile::url
 component no longer causes an infinite loop #4274 Str::excerpt()
does not add superfluous space after stripped tag and before interpunctuation #4645- Fixed calling
A::average()
with empty array #4269 - Site search with parameters now returns correct results #4641
- Caching is no longer disabled when the request passes an empty
Authorization
header. #4634 - Calling
$app->user()
no longer sets the response flag for "uses auth header" unless theapi.basicAuth
option is enabled. #4646 A::append()
has been fixed for non-associative arrays. It is now an alias forA::merge()
with theA::MERGE_APPEND
flag. #4345- Language routes that return a falsy value are only called once now #4305
$translation->exists()
now works for virtual pages #4674- Database queries can now filter by
'AND'
and'OR'
as actual values (via->where()
,->andWhere()
and->orWhere()
) #4668 - Prevent race condition errors for
Dir::make()
#4745
Refactoring
Panel
- Panel drag texts now use UUIDs (KirbyText) or permalinks (Markdown) for absolute references #4612
- Custom login views no longer need to display errors themselves with
k-login-alert
, instead they canthis.$emit("error", error)
#4577 - The properties for the system view are now combined in the backend for easier extension and testing #4658
- Updated npm dependencies #4639
- New blueprint syntax for options (with polyfills for the old syntax): #4624
Core
- Optimized code base to take advantage of PHP 8
- Using PHP
match
statements instead ofswitch
in various places #4452 - UsingÂ
|null
 for nullable type hints #4453 - Using PHP's new null safe operator #4455
Kirby\Toolkit\A
: Improve type hinting #4495- Removed unused variables from PHPÂ
catch
 statements #4457 - Use PHP'sÂ
instanceof
 instead ofÂis_a()
#4609
- Using PHP
- Support for default caches (viaÂ
Core::caches()
) #4535 Kirby\Database\Query
: New third parameter$mode
for->filterQuery()
 #4564- Added a new
Option
namespace with refactored options classes #4624 - New syntax forÂ
Helpers::handleErrors()
:
Deprecated
$kirby->impersonate($user, $callback)
: The$callback
will not be bound anymore to the$kirby
instance in Kirby 3.9.0,$this
inside the callback will refer to the current context and not$kirby
instead. Using$this
as$kirby
inside the callback will throw a deprecation warning in debug mode. #4498- Blueprints: The
headline
option for sections will be removed in a future Kirby version. Uselabel
instead. #4515 $kirby->server()
has been deprecated and will be removed in Kirby 3.9.0. Use$kirby->environment()
instead. #4515Kirby\Form\Options
,Kirby\Form\OptionsApi
,Kirby\Form\OptionsQuery
have been deprecated and will be removed in Kirby 3.9. Use theirKirby\Option
equivalents instead.
Breaking changes
We try to avoid breaking changes as much as we can. But we also put a lot of effort in keeping our technical debt in Kirby as low as possible. Sometimes such breaking changes are necessary to move forward with a clean code base.
You might wonder why there are breaking changes in a minor release according to Semantic Versioning.
We stick to the following versioning scheme:
This release is Kirby 3.8.0.0 (major release 8 of Kirby 3)
Traditionally, we combine patch and minor releases though and only need the fourth versioning level for regression fixes.
Panel
- The multiselect field no longer displays the option value as info #4624
Core
- Kirby 3.8.0 requires a minimum of PHP 8.0.
uuid
andpermalink
 cannot be used as field name or custom method for any page, file, user or site anymore. Content fields can only be accessed via e.g.Â$model->content()->get('permalink')
.- The first-level URL pathÂ
@
 is now blocked. - Kirby's upload sanitizer no longer checks XML files for external links because they can be pretty common in many XML-based formats; if you want to keep the strict behavior, setÂ
Kirby\Sane\Xml::$allowedDomains = []
, set this property to a custom allowlist or write a custom Sane handler for your XML-based format #4553 - Kirby now automatically loads theÂ
site/config/env.php
 file; if you already use this file path for a different purpose, please rename the file to a different name #4580 A::average()
returnsnull
when passed an empty array #4649- The default token fallback in
Str::safeTemplate()
changed from an empty string tonull
(which leaves invalid tokens in the output string). This behavior is consistent withStr::template()
. $translation->exists()
now returnstrue
for translations without an actual content file but where an content array has been provided- The deprecated
master
branch of the Kirby repository was deleted. If you install Kirby via Git, e.g. as a submodule, please use themain
branch instead. - Database queries: subsequent
->where()
clauses don't support passing the mode (AND
|OR
) as last parameter anymore, but will interpret these as actual values to filter against. Use->andWhere()
or->orWhere()
instead. #4668 Helpers::handleErrors()
's 2nd parameter now only determines whether the error is suppressed, its 3rd parameter defines what is returned when an error is suppressed
Removed deprecated code #4478 #4515
Removed dump
component. Disable dump()
via KIRBY_HELPER_DUMP
instead and create your own function.
PHP methods
Removed | Use instead |
---|---|
$file->dragText() |
$file->panel()->dragText() |
$file->panelIcon() |
$file->panel()->image() |
$file->panelImage() |
$file->panel()->image() |
$file->panelOptions() |
$file->panel()->options() |
$file->panelPath() |
$file->panel()->path() |
$file->panelUrl() |
$file->panel()->url() |
$file->pickerData() |
$file->panel()->pickerData() |
$files->findById() |
$files->find() |
$page->dragText() |
$page->panel()->dragText() |
$page->panelIcon() |
$page->panel()->image() |
$page->panelId() |
$page->panel()->id() |
$page->panelImage() |
$page->panel()->image() |
$page->panelOptions() |
$page->panel()->options() |
$page->panelPath() |
$page->panel()->path() |
$page->panelUrl() |
$page->panel()->url() |
$page->pickerData() |
$page->panel()->pickerData() |
$pages->findById() |
$pages->find() |
$pages->findByIdRecursive() |
$pages->find() |
$pages->findByUri() |
$pages->find() |
$site->panelIcon() |
$site->panel()->image() |
$site->panelImage() |
$site->panel()->image() |
$site->panelOptions() |
$site->panel()->options() |
$site->panelPath() |
$site->panel()->path() |
$site->panelUrl() |
$site->panel()->url() |
$site->pickerData() |
$site->panel()->pickerData() |
$user->panelIcon() |
$user->panel()->image() |
$user->panelImage() |
$user->panel()->image() |
$user->panelOptions() |
$user->panel()->options() |
$user->panelPath() |
$user->panel()->path() |
$user->panelUrl() |
$user->panel()->url() |
$user->pickerData() |
$user->panel()->pickerData() |
Kirby\Panel\Document::customCss() |
Kirby\Panel\Document::customAsset('panel.css') |
Kirby\Panel\Document::customJs() |
Kirby\Panel\Document::customAsset('panel.js') |
Kirby\Toolkit\Str::isUrl() |
Kirby\Toolkit\V::url() |
Method | Change | Use instead |
---|---|---|
markdown component |
Removed $inline parameter |
$options['inline'] |
$kirby->kirbytext() |
Removed $inline parameter |
$options['markdown']['inline'] |
$kirby->markdown() |
Passing a boolean as second parameter isn't supported anymore. | $options['inline'] |
Classes
Removed | Use instead |
---|---|
Kirby\Http\Server |
Kirby\Http\Environment |
Class Aliases
Removed |
---|
Server |
API
Removed |
---|
page.next |
page.prev |
Migration from Kirby 3.7.x
To ease the transition, we have compiled everything you need to know in detailed migration guides:
Migration guide for site developers →
Migration guide for plugin developers →