Panel
It's all about editing…
Content locking
Working in teams has become a lot safer with our new content locking feature. Pages that are being edited are now automatically locked and other editors get informed about the editing user and cannot overwrite their ongoing changes.
Conditional sections
You can now create conditional sections that are only shown when a field contains a specific value (i.e. a toggle is checked, a select field is at a certain option, etc.)
Conditional sections work exactly like conditional fields.
sections:
content:
type: fields
fields:
postType:
type: select
options:
- Gallery
- Image
gallery:
type: files
template: gallery-image
layout: cards
size: tiny
when:
postType: Gallery
image:
type: files
template: single-image
max: 1
layout: cards
when:
postType: Image
Duplicating pages
It's often easier to start a new page from existing content than to start from scratch. With the new "Duplicate" function you can now create new drafts from existing pages and decide to also copy files and even subpages.
File uploads in files field
You can now finally upload files directly in the files field.
Better permissions
You can now control each option for pages, files and users with fine-grained permissions:
options:
delete:
admin: true
editor: false
There's also a wildcard available to change the default for all roles:
options:
update:
*: false
editor: true
Monospace option for textareas
fields:
text:
label: Text
type: textarea
font: monospace
Flexible widths for structure columns
You can set any fraction and it will be automatically calculated into the right width.
fields:
mystructure:
label: Structure
type: structure
columns:
a:
width: 3/5
b:
width: 1/5
c:
width: 1/10
d:
width: 1/10
fields:
a:
label: A
type: text
b:
label: B
type: text
c:
label: C
type: text
d:
label: D
type: text
Custom login screen plugins
With the new "login" plugin type you can now swap Kirby's default login screen and add your own. This is perfect when you want to implement your own authentication methods.
Here's a quick example:
index.js
import LoginScreen from "./components/LoginScreen.vue";
panel.plugin('my/auth', {
login: LoginScreen
});
LoginScreen.vue
<template>
<form @submit.prevent="login">
<k-fieldset :fields="fields" @submit="login"></k-fieldset>
<k-button type="submit" icon="check">Authenticate</k-button>
</form>
</template>
<script>
export default {
computed: {
fields() {
return {
phone: {
placeholder: "+49 ",
label: "Phone",
type: "tel"
}
}
}
},
methods: {
login() {
/** Send 2FA auth link **/
}
}
};
</script>
Translatable slugs
Our slug generator now has language specific rules that improve the quality of created slugs drastically. You can combine this with custom rules for each language.
<?php
return [
'code' => 'de',
'default' => false,
'direction' => 'ltr',
'locale' => 'de_DE',
'name' => 'Deutsch',
'slug' => [
'ß' => 'sz'
]
];
For single-language setups you can define which ruleset to use in the config.php
as well as define custom rules:
<?php
return [
'slugs' => 'de'
];
Str::$language = [
'ß' => 'sz'
];
Backend
User and file models and more methods extensions (user, users)
Users and files can now have their own model classes – like pages. Model classes give you full access to extend and overwrite the functionalities of users and files based on their roles or templates.
class EditorUser extends User
{
// ...
}
class CoverFile extends File
{
// ...
}
Kirby::plugin('my/plugin', [
'fileModels' => [
'cover' => 'CoverFile'
],
'userModels' => [
'editor' => 'EditorUser'
],
'usersMethods' => [
'withArticles' => function () {
return $this->articles()->isNotEmpty();
}
]
]);
Multi-Language routing
We drastically simplified routing in multi-language setups. You can now handle routes for a specific language or any language in a matter of seconds without writing redundant route definitions.
return [
'routes' => [
[
'pattern' => '(:any)',
'language' => 'en',
'action' => function ($language, $slug) {
if (page($slug)) {
return $this->next();
}
if ($page = page('notes/' . $slug)) {
return $page;
}
return false;
}
],
]
];
You can even add a page scope to the routes, which will automatically take care to handle translated slugs.
return [
'routes' => [
[
'pattern' => 'tag/(:any)',
'language' => '*',
'page' => 'notes',
'action' => function ($language, $page, $filter) {
return $page->render([
'filter' => $filter
]);
}
],
]
];
Snippet alternatives
You can now define snippet alternatives if the first snippet cannot be found.
<?php snippet(['try/this', 'try/that', 'try/last']) ?>
This is perfect if you want to load a snippet based on a custom page field, but such a snippet might not always exist:
<?php snippet(['articles/' . $page->postType(), 'articles/default']) ?>
Improved query syntax
You can now use array syntax and nested queries in our query syntax.
// arrays
site.index.filterBy('template', 'in', ['note', 'album']);
// nested queries
kirby.collection("some-collection").not(kirby.collection("excluded-collection"))
New query option in users field
The users field gets a lot more flexible with the addition of a query option. You can use this for example to filter users by role or any other custom field.
fields:
author:
label: Author
type: users
query: kirby.users.role("editor")
The option to unset parts of extended blueprints
When you create mixins for blueprints, such as field definitions or entire tabs, you can now use them but unset definitions that you don't want/need.
# /site/blueprints/tabs/seo.yml
label: SEO
icon: search
fields:
seoTitle:
label: SEO Title
type: text
seoDescription:
label: SEO Description
type: text
Then in the extending blueprint …
tabs:
seo:
extends: tabs/seo
fields:
seoDescription: false
New tt()
helper
New tt()
helper as shortcut for I18n::template()
// /site/languages/en.php
return [
'code' => 'en',
'default' => false,
'direction' => 'ltr',
'locale' => 'en_US',
'name' => 'English',
'translations' => [
'alert' => 'Attention: { message }'
]
];
In your templates …
<?= tt('alert', ['message' => 'Something is not right']) ?>
Customizable preview URL for the site.yml
You can already control the preview URL for each page type in the page's blueprint, but in 3.2 you can now also set the same option in the site.yml
title: Site
preview: https://mycustomdomain.com
Additional enhancements and fixes
New
- New option to link to a file in the image tag
(image: myimage.jpg link: mydocument.pdf)
- New
download
option for the file tag to avoid direct downloads:(file: myfile.pdf download: false)
- New fallback parameter for the
$field->toDate('d.m.Y', 'now')
method - Assets from the
asset()
method can now be used as preview images in the Panel - New Users::role() filter shortcut
- New
$kirby->request()->domain()
method - New
$kirby->request()->path()
method - Webp images are now included in
$page->images()
collections - The
route:after
hook can now manipulate the return value - New
Mime::toExtensions()
method - New NullCache and MemoryCache drivers
- New
created
plugin type for Panel plugins, which gives you full access to the Vue instance, the Vue router and Vuex - All panel views can now be overwritten with custom components
- You can now use the
uploadFile.js
helper to upload custom Blobs and pass the name properly in panel plugins.
Improved
- Better resolutions for images in the Panel by using
srcset
for thumbs in lists and cards, so your browser can select the best resolution for you - Faster thumbnail generation logic in templates
- The role title and description of the default admin role is now translated by default
- You can now use dots when renaming files in the Panel
- Improved performance of options for select fields, radio buttons, tags and checkboxes
- Attributes in KirbyTags are no longer case-sensitive.
(Image: something.jpg)
works as well as(image: something.jpg)
- The Html::a() method now accepts
tel:
andmailto:
links - The empty option in a select input is now automatically disabled when the field is required
- Better visual structure in the page options dropdown
- Better validation and error messages in the registration dialog
- All caches are now properly prefixed to avoid collissions in multi-site installations
- The localStorage is automatically cleared when the user logs out.
- All Vue components are now registered globally to allow overwriting them. This is especially useful for the textarea toolbar components.
- The login throws more useful exceptions when Kirby is in debug mode
- Invalid parent queries in Pages sections throw a useful error now
- HMR is now possible in panel plugins with our new pluginkit
- Better disabled state for toggle fields
- Better cache busting mode in API requests
- Better error handling in error boundaries. (Throws warnings instead of errors to avoid breaking the panel)
- Increased backend test coverage to 85%
Fixed
- Form buttons are now disabled when the content cannot be edited
help
in sections gets translated correctly now- The buttons in textareas no longer wrap in narrow columns
- The toolbar in textareas is now automatically hidden, when the field is disabled.
- The default values in the toggle input are now translated correctly
- The dimensions of JPG2000 files are now correctly displayed in the file view
- Users are now sorted correctly in the users overview
- Plugin options are now available in API routes
- Thumbnails are no longer regenerated when the file meta content changes
- The language modal can now correctly handle single locale settings again
- Sections are now really loaded asynchronously
- Fix Url detection in virtual host setup
- Check if a thumbnail is actually created and retry if not
- Language values are now validated correctly when a new language is created
- The template option works now correctly in files presets
Notices and breaking changes
- Content locking only works between users. It will not prevent you to overwrite unsaved changes from another device or browser window.
- Query syntax: always wrap strings in quotes, preferably double quotes
translations
root deprecated and will be removed in 3.3. Usei18n:translations
insteadFile::model()
does no longer return the parent model. UseFile::parent()
instead