Update to Kirby 5

This commit is contained in:
Paul Nicoué 2025-07-11 14:41:34 +02:00
parent 5d9979fca8
commit 0fefc5e2e1
472 changed files with 30853 additions and 10301 deletions

View file

@ -0,0 +1,72 @@
<?php
use Kirby\Cms\ModelWithContent;
use Kirby\Cms\Page;
use Kirby\Cms\Site;
use Kirby\Panel\Ui\Buttons\LanguagesDropdown;
use Kirby\Panel\Ui\Buttons\OpenButton;
use Kirby\Panel\Ui\Buttons\PageStatusButton;
use Kirby\Panel\Ui\Buttons\PreviewButton;
use Kirby\Panel\Ui\Buttons\SettingsButton;
use Kirby\Panel\Ui\Buttons\VersionsButton;
return [
'site.open' => function (Site $site, string $versionId = 'latest') {
$versionId = $versionId === 'compare' ? 'changes' : $versionId;
$link = $site->previewUrl($versionId);
if ($link !== null) {
return new OpenButton(
link: $link,
);
}
},
'site.preview' => function (Site $site) {
if ($site->previewUrl() !== null) {
return new PreviewButton(
link: $site->panel()->url(true) . '/preview/changes',
);
}
},
'site.versions' => function (Site $site, string $versionId = 'latest') {
return new VersionsButton(
model: $site,
versionId: $versionId
);
},
'page.open' => function (Page $page, string $versionId = 'latest') {
$versionId = $versionId === 'compare' ? 'changes' : $versionId;
$link = $page->previewUrl($versionId);
if ($link !== null) {
return new OpenButton(
link: $link,
);
}
},
'page.preview' => function (Page $page) {
if ($page->previewUrl() !== null) {
return new PreviewButton(
link: $page->panel()->url(true) . '/preview/changes',
);
}
},
'page.versions' => function (Page $page, string $versionId = 'latest') {
return new VersionsButton(
model: $page,
versionId: $versionId
);
},
'page.settings' => fn (Page $page) => new SettingsButton(model: $page),
'page.status' => fn (Page $page) => new PageStatusButton($page),
// `languages` button needs to be in site area,
// as the languages might be not loaded even in
// multilang mode when the `languages` option is deactivated
// (but content languages to switch between still can exist)
'languages' => fn (ModelWithContent $model) =>
new LanguagesDropdown($model),
// file buttons
...require __DIR__ . '/../files/buttons.php'
];

View file

@ -28,12 +28,10 @@ return [
$page = Find::page($id);
if ($page->blueprint()->num() !== 'default') {
throw new PermissionException([
'key' => 'page.sort.permission',
'data' => [
'slug' => $page->slug()
]
]);
throw new PermissionException(
key: 'page.sort.permission',
data: ['slug' => $page->slug()]
);
}
return [
@ -150,12 +148,10 @@ return [
$blueprints = $page->blueprints();
if (count($blueprints) <= 1) {
throw new Exception([
'key' => 'page.changeTemplate.invalid',
'data' => [
'slug' => $id
]
]);
throw new Exception(
key: 'page.changeTemplate.invalid',
data: ['slug' => $id]
);
}
return [
@ -264,20 +260,17 @@ return [
// the page title changed
if ($page->title()->value() !== $title) {
$page->changeTitle($title);
$page = $page->changeTitle($title);
$response['event'][] = 'page.changeTitle';
}
// the slug changed
if ($page->slug() !== $slug) {
$newPage = $page->changeSlug($slug);
$response['event'][] = 'page.changeSlug';
$response['dispatch'] = [
'content/move' => [
$oldUrl = $page->panel()->url(true),
$newUrl = $newPage->panel()->url(true)
]
];
$newPage = $page->changeSlug($slug);
$oldUrl = $page->panel()->url(true);
$newUrl = $newPage->panel()->url(true);
// check for a necessary redirect after the slug has changed
if (Panel::referrer() === $oldUrl && $oldUrl !== $newUrl) {
@ -372,7 +365,9 @@ return [
$page->childrenAndDrafts()->count() > 0 &&
$request->get('check') !== $page->title()->value()
) {
throw new InvalidArgumentException(['key' => 'page.delete.confirm']);
throw new InvalidArgumentException(
key: 'page.delete.confirm'
);
}
$page->delete(true);
@ -385,7 +380,6 @@ return [
return [
'event' => 'page.delete',
'dispatch' => ['content/remove' => [$url]],
'redirect' => $redirect
];
}
@ -416,19 +410,17 @@ return [
if ($hasFiles === true) {
$fields['files'] = [
'label' => I18n::translate('page.duplicate.files'),
'type' => 'toggle',
'required' => true,
'width' => $toggleWidth
'label' => I18n::translate('page.duplicate.files'),
'type' => 'toggle',
'width' => $toggleWidth
];
}
if ($hasChildren === true) {
$fields['children'] = [
'label' => I18n::translate('page.duplicate.pages'),
'type' => 'toggle',
'required' => true,
'width' => $toggleWidth
'label' => I18n::translate('page.duplicate.pages'),
'type' => 'toggle',
'width' => $toggleWidth
];
}
@ -440,11 +432,11 @@ return [
$duplicateSlug = $page->slug() . '-' . $slugAppendix;
$siblingKeys = $page->parentModel()->childrenAndDrafts()->pluck('uid');
if (in_array($duplicateSlug, $siblingKeys) === true) {
if (in_array($duplicateSlug, $siblingKeys, true) === true) {
$suffixCounter = 2;
$newSlug = $duplicateSlug . $suffixCounter;
while (in_array($newSlug, $siblingKeys) === true) {
while (in_array($newSlug, $siblingKeys, true) === true) {
$newSlug = $duplicateSlug . ++$suffixCounter;
}
@ -556,13 +548,7 @@ return [
return [
'event' => 'page.move',
'redirect' => $newPage->panel()->url(true),
'dispatch' => [
'content/move' => [
$oldPage->panel()->url(true),
$newPage->panel()->url(true)
]
],
'redirect' => $newPage->panel()->url(true)
];
}
],
@ -643,13 +629,7 @@ return [
'changes' => [
'pattern' => 'changes',
'load' => function () {
$dialog = new ChangesDialog();
return $dialog->load();
return (new ChangesDialog())->load();
},
'submit' => function () {
$dialog = new ChangesDialog();
$ids = App::instance()->request()->get('ids');
return $dialog->submit($ids);
}
],
];

View file

@ -1,5 +1,8 @@
<?php
use Kirby\Cms\App;
use Kirby\Cms\Find;
use Kirby\Panel\Ui\Buttons\LanguagesDropdown;
$files = require __DIR__ . '/../files/dropdowns.php';
@ -10,12 +13,34 @@ return [
return Find::page($path)->panel()->dropdown();
}
],
'page.languages' => [
'pattern' => 'pages/(:any)/languages',
'options' => function (string $path) {
$page = Find::page($path);
return (new LanguagesDropdown($page))->options();
}
],
'page.file' => [
'pattern' => '(pages/.*?)/files/(:any)',
'options' => $files['file']
],
'page.file.languages' => [
'pattern' => '(pages/.*?)/files/(:any)/languages',
'options' => $files['language']
],
'site.languages' => [
'pattern' => 'site/languages',
'options' => function () {
$site = App::instance()->site();
return (new LanguagesDropdown($site))->options();
}
],
'site.file' => [
'pattern' => '(site)/files/(:any)',
'options' => $files['file']
],
'site.file.languages' => [
'pattern' => '(site)/files/(:any)/languages',
'options' => $files['language']
]
];

View file

@ -1,90 +1,25 @@
<?php
use Kirby\Cms\App;
use Kirby\Cms\Find;
use Kirby\Toolkit\I18n;
use Kirby\Panel\Controller\PageTree;
return [
// @codeCoverageIgnoreStart
// TODO: move to controller class and add unit tests
'tree' => [
'pattern' => 'site/tree',
'action' => function () {
$kirby = App::instance();
$request = $kirby->request();
$move = $request->get('move');
$move = $move ? Find::parent($move) : null;
$parent = $request->get('parent');
if ($parent === null) {
$site = $kirby->site();
$panel = $site->panel();
$uuid = $site->uuid()?->toString();
$url = $site->url();
$value = $uuid ?? '/';
return [
[
'children' => $panel->url(true),
'disabled' => $move?->isMovableTo($site) === false,
'hasChildren' => true,
'icon' => 'home',
'id' => '/',
'label' => I18n::translate('view.site'),
'open' => false,
'url' => $url,
'uuid' => $uuid,
'value' => $value
]
];
}
$parent = Find::parent($parent);
$pages = [];
foreach ($parent->childrenAndDrafts()->filterBy('isListable', true) as $child) {
$panel = $child->panel();
$uuid = $child->uuid()?->toString();
$url = $child->url();
$value = $uuid ?? $child->id();
$pages[] = [
'children' => $panel->url(true),
'disabled' => $move?->isMovableTo($child) === false,
'hasChildren' => $child->hasChildren() === true || $child->hasDrafts() === true,
'icon' => $panel->image()['icon'] ?? null,
'id' => $child->id(),
'open' => false,
'label' => $child->title()->value(),
'url' => $url,
'uuid' => $uuid,
'value' => $value
];
}
return $pages;
return (new PageTree())->children(
parent: App::instance()->request()->get('parent'),
moving: App::instance()->request()->get('move')
);
}
],
'tree.parents' => [
'pattern' => 'site/tree/parents',
'action' => function () {
$kirby = App::instance();
$request = $kirby->request();
$root = $request->get('root');
$page = $kirby->page($request->get('page'));
$parents = $page?->parents()->flip()->values(
fn ($parent) => $parent->uuid()?->toString() ?? $parent->id()
) ?? [];
// if root is included, add the site as top-level parent
if ($root === 'true') {
array_unshift($parents, $kirby->site()->uuid()?->toString() ?? '/');
}
return [
'data' => $parents
];
return (new PageTree())->parents(
page: App::instance()->request()->get('page'),
includeSite: App::instance()->request()->get('root') === 'true',
);
}
]
// @codeCoverageIgnoreEnd
];

View file

@ -1,56 +1,17 @@
<?php
use Kirby\Cms\App;
use Kirby\Toolkit\Escape;
use Kirby\Panel\Controller\Search;
use Kirby\Toolkit\I18n;
return [
'pages' => [
'label' => I18n::translate('pages'),
'icon' => 'page',
'query' => function (string|null $query, int $limit, int $page) {
$kirby = App::instance();
$pages = $kirby->site()
->index(true)
->search($query)
->filter('isListable', true)
->paginate($limit, $page);
return [
'results' => $pages->values(fn ($page) => [
'image' => $page->panel()->image(),
'text' => Escape::html($page->title()->value()),
'link' => $page->panel()->url(true),
'info' => Escape::html($page->id()),
'uuid' => $page->uuid()?->toString(),
]),
'pagination' => $pages->pagination()->toArray()
];
}
'query' => fn (string|null $query, int $limit, int $page) => Search::pages($query, $limit, $page)
],
'files' => [
'label' => I18n::translate('files'),
'icon' => 'image',
'query' => function (string|null $query, int $limit, int $page) {
$kirby = App::instance();
$files = $kirby->site()
->index(true)
->filter('isListable', true)
->files()
->filter('isListable', true)
->search($query)
->paginate($limit, $page);
return [
'results' => $files->values(fn ($file) => [
'image' => $file->panel()->image(),
'text' => Escape::html($file->filename()),
'link' => $file->panel()->url(true),
'info' => Escape::html($file->id()),
'uuid' => $file->uuid()->toString(),
]),
'pagination' => $files->pagination()->toArray()
];
}
'query' => fn (string|null $query, int $limit, int $page) => Search::files($query, $limit, $page)
]
];

View file

@ -2,6 +2,9 @@
use Kirby\Cms\App;
use Kirby\Cms\Find;
use Kirby\Exception\PermissionException;
use Kirby\Panel\Ui\Buttons\ViewButtons;
use Kirby\Toolkit\I18n;
return [
'page' => [
@ -14,6 +17,40 @@ return [
return Find::file('pages/' . $id, $filename)->panel()->view();
}
],
'page.preview' => [
'pattern' => 'pages/(:any)/preview/(changes|latest|compare)',
'action' => function (string $path, string $versionId) {
$page = Find::page($path);
$view = $page->panel()->view();
$src = [
'latest' => $page->previewUrl('latest'),
'changes' => $page->previewUrl('changes'),
];
if ($src['latest'] === null) {
throw new PermissionException('The preview is not available');
}
return [
'component' => 'k-preview-view',
'props' => [
...$view['props'],
'back' => $view['props']['link'],
'buttons' => fn () =>
ViewButtons::view('page.preview', model: $page)
->defaults(
'page.versions',
'languages',
)
->bind(['versionId' => $versionId])
->render(),
'src' => $src,
'versionId' => $versionId,
],
'title' => $view['props']['title'] . ' | ' . I18n::translate('preview'),
];
}
],
'site' => [
'pattern' => 'site',
'action' => fn () => App::instance()->site()->panel()->view()
@ -24,4 +61,38 @@ return [
return Find::file('site', $filename)->panel()->view();
}
],
'site.preview' => [
'pattern' => 'site/preview/(changes|latest|compare)',
'action' => function (string $versionId) {
$site = App::instance()->site();
$view = $site->panel()->view();
$src = [
'latest' => $site->previewUrl('latest'),
'changes' => $site->previewUrl('changes'),
];
if ($src['latest'] === null) {
throw new PermissionException('The preview is not available');
}
return [
'component' => 'k-preview-view',
'props' => [
...$view['props'],
'back' => $view['props']['link'],
'buttons' => fn () =>
ViewButtons::view('site.preview', model: $site)
->defaults(
'site.versions',
'languages'
)
->bind(['versionId' => $versionId])
->render(),
'src' => $src,
'versionId' => $versionId
],
'title' => I18n::translate('view.site') . ' | ' . I18n::translate('preview'),
];
}
],
];