Skip to content

@bastianallgeier bastianallgeier released this Jun 25, 2019 · 22 commits to master since this release


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.

    type: fields
        type: select
          - Gallery
          - Image
    type: files
    template: gallery-image
    layout: cards
    size: tiny
      postType: Gallery
    type: files
    template: single-image
    max: 1    
    layout: cards
      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:

    admin: true
    editor: false

There's also a wildcard available to change the default for all roles:

    *: false
    editor: true

Monospace option for textareas


    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.


    label: Structure
    type: structure
        width: 3/5		
        width: 1/5
        width: 1/10
        width: 1/10
        label: A
        type: text
        label: B
        type: text
        label: C
        type: text
        label: D
        type: text

Custom login screen plugins

Screenshot 2019-06-04 at 13 39 46

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:


import LoginScreen from "./components/LoginScreen.vue";

panel.plugin('my/auth', {
  login: LoginScreen


  <form @submit.prevent="login">
    <k-fieldset :fields="fields" @submit="login"></k-fieldset>
    <k-button type="submit" icon="check">Authenticate</k-button>

export default {
  computed: {
    fields() {
      return {
        phone: {
          placeholder: "+49 ",
          label: "Phone",
          type: "tel"
  methods: {
    login() {
      /** Send 2FA auth link **/

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.


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:


return [
  'slugs' => 'de'

Str::$language = [
  'ß' => 'sz' 


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

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.

    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
    label: SEO Title
    type: text
    label: SEO Description
    type: text

Then in the extending blueprint …

    extends: tabs/seo
      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

Additional enhancements and fixes


  • 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.


  • 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: and mailto: 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%


  • 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. Use i18n:translations instead
  • File::model() does no longer return the parent model. Use File::parent() instead
Assets 2
You can’t perform that action at this time.