github getkirby/kirby 5.2.0-rc.1

pre-release5 hours ago

🤩 Highlights

  • 🐘 PHP 8.5 support
  • 📻 CORS support
  • ☑️ New batch select mode for the checkboxes field
  • ↕️ Collapse / expand all blocks
  • 📂 New create option for the files section
  • 🏷️ Better auto-labels in the Panel
  • ⚡️ Big performance boost for forms

🎉 Features

PHP 8.5 support

PHP 8.5 has been released a few days ago and it's a fantastic release (https://www.php.net/releases/8.5/en.php) Kirby 5.2 is already fully compatible. #7671

Automatic handling of CORS (Cross-Origin Resource Sharing)

For headless setups, proper CORS support is incredibly helpful to speak to your Kirby API, content representations or KQL across domains. Thanks to the help of @johannschopplich, Kirby is now making this very easy out of the box.

How It Works

  1. Simple setup: Set 'cors' => true to enable CORS with sensible defaults. Check below for additional configuration options.
  2. Automatic preflight handling: When CORS is enabled, all OPTIONS CORS preflight requests automatically receive a 204 No Content response with appropriate CORS headers.
  3. Header injection: CORS headers are lazily injected into the Responder::headers() method for all responses. Custom headers set by plugins or user code are never overridden.
  4. Vary header management (Hono inspired):
    • Wildcard origins (*): No Vary: Origin header is added (cache-efficient since response is identical for all origins)
    • Specific origins: Automatic Vary: Origin header ensures different origins are cached separately
    • Header reflection: Automatic Vary: Access-Control-Request-Headers for preflight requests when reflection is enabled
    • Auth/Cookie tracking: Automatic Vary: Authorization, Cookie when response uses authentication or cookies
    • Smart merging: All Vary values are combined intelligently without duplication
  5. Header reflection opt-in: With 'allowHeaders' => true, preflight requests mirror the headers requested by the client while Vary: Access-Control-Request-Headers ensures correct caching. The default [] remains secure-by-default by omitting the header.

Configuration

CORS can be enabled in three ways:

1. Boolean (uses all defaults)
return [
    'cors' => true
];
2. Array (custom configuration)
return [
    'cors' => [
        'allowOrigin'      => 'https://example.com',
        'allowCredentials' => true
    ]
];
3. Closure (dynamic/request-based)
return [
    'cors' => function ($kirby) {
        $origin = $kirby->request()->header('Origin');

        // Allow specific origins with credentials
        if (in_array($origin, ['https://app1.com', 'https://app2.com'])) {
            return [
                'allowOrigin'      => $origin,
                'allowCredentials' => true,
                'allowMethods'     => ['GET', 'POST']
            ];
        }

        // Fallback to wildcard for other origins
        return ['allowOrigin' => '*'];
    }
];

Note: Setting 'cors' => [] (empty array) is equivalent to 'cors' => true and enables CORS with defaults. To disable CORS, use 'cors' => false or omit the option entirely.

Available Options

Option Type Default Description
allowOrigin string, array '*' Allowed origins (e.g., '*', 'https://example.com', or ['https://app1.com', 'https://app2.com'] for multiple origins)
allowMethods string, array ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'] Allowed HTTP methods for preflight requests
allowHeaders string, array, bool [] Allowed request headers. [] (default) suppresses Access-Control-Allow-Headers; true reflects headers from Access-Control-Request-Headers; strings/arrays allowlist specific headers explicitly
maxAge int null Preflight cache duration in seconds. null uses the browser default (typically 5 seconds)
allowCredentials bool false Allow requests with credentials (cookies, auth). Cannot be true with wildcard origin
exposeHeaders string, array [] Response headers exposed to the browser

Security considerations:

  • Enabling CORS allows external origins to interact with your Kirby site. This means that sites hosted on external origins (domains) can access or control your Kirby site via the browser of their visitors. Only enable CORS when needed, and restrict the configuration (origins, methods, headers) to the minimum required for your use case.
  • 'allowCredentials' => true lets browsers include cookies and HTTP authentication with cross-origin requests, effectively granting the external origin the same permissions as the logged-in user. Only enable credentials when the requesting origin is fully trusted and under your control.

New batch select mode for the checkboxes field

You can now switch on the select all/deselect all toggles with the new batch option in the checkboxes field to select or deselect multiple checkboxes at once. This is helpful when a checkboxes field has a lot of options https://feedback.getkirby.com/81 #7659

fields: 
  countries: 
    type: checkboxes
    options: 
      # lots of countries 
    batch: true
checkboxes.mp4

Thanks to this new feature, we now also have the following additions:

  • New select-all and deselect-all icons
  • New select.all, deselect.all and deselect translation strings

Collapse / expand all blocks

There are new options to expand or collapse all blocks at once in the blocks options dropdown (if there are collapsible blocks used, e.g. with preview: fields) (thx @dennisbaum) #7555

collapse-all

New create option for the files section

The new create option for the files section lets you disable the upload button. This is useful if you are using queries in files sections and the upload would not actually show up in the list. It is comparable to the create option in the pages section. #7649

sections: 
  images: 
    type: files
    query: page.images.filter('customField', 'customFilter')
    create: false

Better auto-labels in the Panel

We've improved our auto-labelling method for labels, titles and more in various places of the Panel. Here's an example from a blueprint #7656:

sections:
  coverImages: 
    type: files

The files section above does not define a label, but already has a meaningful name, which can now be turned into one. In previous releases coverImages would have been turned into the auto-label Coverimages. Not that nice. Now camel casing automatically turns it into Cover images. This also works if you prefer kebab-casing.

sections:
  cover_images: 
    type: files

This will very often save you from defining additional label/title/name options. This can now help you in the following places:
- Blueprint title
- Blueprint tab labels
- Section headlines
- Form field labels
- Block field: fieldset names
- Block field: fieldset tab names
- Block field: fieldset group names
- Role titles
- Custom panel search labels

This feature is based on our new Kirby\Toolkit\Str::label() method, which you can of course use in your own code, to create nice auto-labels.


⚡️ Performance

We've managed to achieve massive performance improvements for forms. In our test setup we measure two different scenarios:

1. Generating the backend props for all fields and their custom configurations.

5.1.4: 00:06.198
5.2.0: 00:03.045

≈ 50.9% reduction in time
≈ 2.04× speed-up

2. Generating the backend props for all our field related panel views.

5.1.4: 00:19.390
5.2.0: 00:05.900

≈ 69.6% reduction in time
≈ 3.29× speed-up

Our test sandbox is of course a very theoretical environment, but we still expect to see some serious improvements in real-world setups.

The following steps lead to this improvement:
- New ::emptyValue() method for Kirby\Form\Field and Kirby\Form\FieldClass, which can be overwritten to define the preferred empty value when the field is being reset #7663
- New Kirby\Form\Field::fillWithEmptyValue() and Kirby\Form\FieldClass:reset(), which are used in Kirby\Form\Fields to reset field values without evaluating computed props again if not
necessary. This is the part that leads to the performance improvements. #7663
- Field options are now cached in memory to improve the performance of fields. #7664
- New protected BlocksField::fieldsetForm method to cache forms for each fieldset type. #7665
- Fixes: #7641 and #6734

We've also added a new in-memory snippet cache to speed up snippet lookups and avoid disk access #7369


✨ Enhancements

  • Plugin links point to plugins.getkirby.com directory if plugin is listed there #7243
  • View button: options string supports Kirby query syntax #7566
  • k-dropdown-item supports all button props (esp. dialog and drawer) #7590
  • New Kirby\Http\Uri::inherit() methods that copies over query, params and fragment from another URL #7611
  • New Kirby\Reflection\Constructor class #7620
use Kirby\Reflection\Constructor;

class Reflectable
{
  public function __construct(
      protected $a,
      protected $b
  ) {
  }
}

$constructor = new Constructor(Reflectable::class);

$constructor->getAcceptedArguments([
  'a' => 'Test A',
  'b' => 'Test B',
  'c' => 'Test C'
]);
// will keep 'a' and 'b'

$constructor->getIgnoredArguments([
  'a' => 'Test A',
  'b' => 'Test B',
  'c' => 'Test C'
]);
// will keep 'c'
  • The PHP version check can now temporarily be disabled with a new KIRBY_PHP_VERSION_CHECK constant. This is for very specific cases and comes with risks, please note the code comment in bootstrap.php. #7648
  • New Kirby\Image\Gravity enum #7732
  • t() helper accepts array for $fallback #7717

🐛 Bug fixes

  • Blocks field: when pasting blocks into a nested blocks field it is now ensured that only one blocks field receives the pasted content, not nested and parent blocks field both. #7093
  • Fixed query support for default option of the number, date and time fields #7594
  • The RequestError JS class is polyfilling error messages stored in the error prop instead of the message prop to create more consistency. #7670
  • The RequestError JS class is now responsible for all server errors to add another layer of consistency there. #7670
  • The details array from custom Kirby Exceptions is now always properly passed forward in all error responses. #7670
  • The panel.notification.error() method is now also passing details forward to the error object. #7670
  • Fixed cropping with imagick thumb driver #7732
  • Handle malformed images gracefully on upload #7724 (thanks to @Stalin-143)
    • Kirby\Image\Image::imagesize() now returns array|false
    • Kirby\Image\Dimensions::forImage() returns 0x0 for invalid images
    • Kirby\Image\Image::isResizable() checks for zero dimensions early

♻️ Refactored

  • k-button supports dialog/drawer objects as props #7590
  • $panel.dialog.open()/$panel.drawer.open() accept a single object argument if it has a url key #7590
  • Code quality fixes #7678

🧹 Housekeeping

  • Removed use of old PHP functions that are deprecated in PHP 8.5 #7556
  • Removed PHPBench tests in favor of Sandbox CLI bench setup #7667
  • Running PHP CS Fixer in parallel now #7677
  • Upgraded to Psalm 6 #7672
  • New error handling examples in the lab (/panel/lab/internals/errors) for various scenarios (opening views, dialogs, drawers, sending requests, etc.) #7670
  • Upgraded PHP dependencies
  • Upgraded JS dependencies

Don't miss a new kirby release

NewReleases is sending notifications on new releases.