SEO Meta Knight
All checks were successful
Deploy / deploy (push) Successful in 29s

This commit is contained in:
Julie Blanc 2026-06-29 20:05:56 +02:00
parent 5126c3659f
commit 15e84f116a
377 changed files with 19088 additions and 1264 deletions

View file

@ -23,7 +23,8 @@
},
"require": {
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"getkirby/cms": "^5.2"
"getkirby/cms": "^5.2",
"fabianmichael/kirby-meta": "^2.0"
},
"config": {
"allow-plugins": {

1286
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
"description": "The Kirby core",
"license": "proprietary",
"type": "kirby-cms",
"version": "5.4.3",
"version": "5.4.4",
"keywords": [
"kirby",
"cms",
@ -45,7 +45,7 @@
"michelf/php-smartypants": "1.8.1",
"phpmailer/phpmailer": "7.1.1",
"symfony/polyfill-intl-idn": "1.38.1",
"symfony/polyfill-mbstring": "1.38.1",
"symfony/polyfill-mbstring": "1.38.2",
"symfony/yaml": "7.4.13"
},
"replace": {

14
kirby/composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "4b4b85db0273b5616f4f99359b7bf084",
"content-hash": "5df022c5288d6ced9b7cae6129d5c94e",
"packages": [
{
"name": "christian-riesen/base32",
@ -949,16 +949,16 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.38.1",
"version": "v1.38.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92"
"reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/14c5439eec4ccff081ac14eca2dc57feb2a66d92",
"reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
"reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
"shasum": ""
},
"require": {
@ -1010,7 +1010,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.1"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2"
},
"funding": [
{
@ -1030,7 +1030,7 @@
"type": "tidelift"
}
],
"time": "2026-05-26T12:51:13+00:00"
"time": "2026-05-27T06:59:30+00:00"
},
{
"name": "symfony/yaml",

View file

@ -58,7 +58,7 @@ return [
'pattern' => 'site/find',
'method' => 'POST',
'action' => function () {
return $this->site()->find(false, ...$this->requestBody());
return $this->site()->find(false, ...$this->requestBody())->filter('isAccessible', true);
}
],
[

View file

@ -1,6 +1,7 @@
<?php
use Kirby\Cms\App;
use Kirby\Http\Cookie;
use Kirby\Panel\Ui\Buttons\ViewButtons;
use Kirby\Toolkit\I18n;
@ -111,6 +112,24 @@ return [
];
}
if ($kirby->option('content.salt') === null) {
$security[] = [
'id' => 'content-salt',
'link' => 'https://getkirby.com/security/content-salt',
'text' => I18n::translate('system.issues.content.salt'),
'theme' => 'notice'
];
}
if (Cookie::$key === 'KirbyHttpCookieKey') {
$security[] = [
'id' => 'cookie-key',
'link' => 'https://getkirby.com/security/cookie-key',
'text' => I18n::translate('system.issues.cookie.key'),
'theme' => 'notice'
];
}
// sensitive URLs
if ($isLocal === false) {
$sensitive = [

View file

@ -5,6 +5,7 @@ use Kirby\Cms\Url;
use Kirby\Exception\NotFoundException;
use Kirby\Text\KirbyTag;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Escape;
use Kirby\Toolkit\Str;
use Kirby\Uuid\Uuid;
@ -23,7 +24,9 @@ return [
return date('Y');
}
return date($tag->date);
// escape the formatted date to prevent injecting HTML
// through special characters in the tag value
return Escape::html(date($tag->date));
}
],

View file

@ -693,6 +693,8 @@
"system.info.copy": "Copy info",
"system.info.copied": "System info copied",
"system.issues.content": "The content folder seems to be exposed",
"system.issues.content.salt": "The content salt has not been changed from its default value",
"system.issues.cookie.key": "The cookie signing key has not been changed from its default value",
"system.issues.eol.kirby": "Your installed Kirby version has reached end-of-life and will not receive further security updates",
"system.issues.eol.plugin": "Your installed version of the { plugin } plugin is has reached end-of-life and will not receive further security updates",
"system.issues.eol.php": "Your installed PHP release { release } has reached end-of-life and will not receive further security updates",

View file

@ -204,7 +204,7 @@
"error.page.undefined": "P\u00e1gina n\u00e3o encontrada",
"error.page.update.permission": "Você não tem permissão para atualizar \"{slug}\"",
"error.role.notFound": "The role \"{name}\" cannot be found",
"error.role.notFound": "A função \"{name}\" não foi encontrada",
"error.section.files.max.plural": "Você não pode adicionar mais do que {max} arquivos à seção \"{section}\"",
"error.section.files.max.singular": "Você não pode adicionar mais do que um arquivo à seção \"{section}\"",
@ -221,7 +221,7 @@
"error.site.changeTitle.empty": "O título não pode ficar em branco",
"error.site.changeTitle.permission": "Você não tem permissão para alterar o título do site",
"error.site.notAccessible": "The site is not accessible",
"error.site.notAccessible": "O site não está acessível",
"error.site.update.permission": "Você não tem permissão para atualizar o site",
"error.structure.validation": "Existe um erro no campo \"{field}\" na linha {index}",

View file

@ -204,7 +204,7 @@
"error.page.undefined": "Não foi possível encontrar a página",
"error.page.update.permission": "Não tem permissões para atualizar \"{slug}\"",
"error.role.notFound": "The role \"{name}\" cannot be found",
"error.role.notFound": "A função \"{name}\" não foi encontrada",
"error.section.files.max.plural": "Não pode adicionar mais do que {max} ficheiros à secção \"{section}\"",
"error.section.files.max.singular": "Não pode adicionar mais do que um ficheiro à secção \"{section}\"",
@ -221,7 +221,7 @@
"error.site.changeTitle.empty": "O título não pode ficar em branco",
"error.site.changeTitle.permission": "Não tem permissões para alterar o título do site",
"error.site.notAccessible": "The site is not accessible",
"error.site.notAccessible": "O site não está acessível",
"error.site.update.permission": "Não tem permissões para atualizar o site",
"error.structure.validation": "Existe um erro no campo \"{field}\" na linha {index}",

View file

@ -204,7 +204,7 @@
"error.page.undefined": "Stranica ne može biti pronađena",
"error.page.update.permission": "Nije Vam dozvoljeno da ažurirate \"{slug}\"",
"error.role.notFound": "The role \"{name}\" cannot be found",
"error.role.notFound": "Uloga \"{name}\" nije pronađjena",
"error.section.files.max.plural": "Ne možete dodati više od {max} fajlova u \"{section}\" sekciju",
"error.section.files.max.singular": "Ne možete dodati više od jednog fajla u \"{section}\" sekciju",
@ -221,7 +221,7 @@
"error.site.changeTitle.empty": "Naslov ne može biti prazan",
"error.site.changeTitle.permission": "Nije Vam dozvoljeno da promenite naziv sajta",
"error.site.notAccessible": "The site is not accessible",
"error.site.notAccessible": "Sajt nije dostupan",
"error.site.update.permission": "Nije Vam dozvoljeno da ažurirate sajt",
"error.structure.validation": "Postoji greška u redu \"{field}\" na ovom polju {index}",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -430,6 +430,15 @@ class App
$default .= '/' . $model->id();
}
// The content path is used as the default salt intentionally: there is
// no install step during which a random salt could be generated and
// persisted. Kirby goes live the moment files are present on the server,
// so there is no defined point at which to write a one-time secret.
// Config files are typically kept in version control and cannot be
// written by the system without causing merge conflicts. No value in
// $_SERVER is both universally available across hosting environments and
// stable enough to serve as a salt. Sites with security requirements
// must set the content.salt option to a secret random value.
$salt = $this->option('content.salt', $default);
if ($salt instanceof Closure) {
@ -1312,6 +1321,17 @@ class App
// try to resolve clean URLs to files for pages and drafts
if ($page = $site->findPageOrDraft($id)) {
// don't leak files on draft pages through clean URLs:
// only serve them to an authenticated user with access
// permission or a request with a valid preview token
if (
$page->isDraft() === true &&
($this->user() && $page->isAccessible()) === false &&
$page->renderVersionFromRequest() === null
) {
return null;
}
return $this->resolveFile($page->file($filename));
}

View file

@ -30,6 +30,7 @@ class Blueprint
public static array $loaded = [];
protected array $fields = [];
protected array|null $fieldsLower = null;
protected ModelWithContent $model;
protected array $props;
protected array $sections = [];
@ -366,7 +367,13 @@ class Blueprint
*/
public function field(string $name): array|null
{
return $this->fields[$name] ?? null;
if (isset($this->fields[$name]) === true) {
return $this->fields[$name];
}
// field objects use normalized lowercase keys
$this->fieldsLower ??= array_change_key_case($this->fields);
return $this->fieldsLower[Str::lower($name)] ?? null;
}
/**

View file

@ -35,6 +35,10 @@ class Item
protected string $id;
protected array $params;
protected ModelWithContent $parent;
/**
* @var TCollection
*/
protected Items $siblings;
/**
@ -102,7 +106,7 @@ class Item
* Returns the sibling collection
* This is required by the HasSiblings trait
*
* @psalm-return self::ITEMS_CLASS
* @return TCollection
*/
protected function siblingsCollection(): Items
{

View file

@ -3,6 +3,7 @@
namespace Kirby\Cms;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\PermissionException;
/**
* The PagePicker class helps to
@ -194,13 +195,33 @@ class PagePicker extends Picker
/**
* Returns the parent model.
* The model will be used to fetch
* subpages unless there's a specific
* query to find pages instead.
* The model will be used to fetch subpages unless there's
* a specific query to find pages instead. Falls back to the
* site root when the requested parent is missing or not
* accessible for the current user.
*
* @throws \Kirby\Exception\PermissionException if neither the requested parent
* nor the site are accessible
*/
public function parent(): Page|Site
{
return $this->parent ??= $this->kirby->page($this->options['parent']) ?? $this->site;
if ($this->parent !== null) {
return $this->parent;
}
$page = $this->kirby->page($this->options['parent']);
if ($page?->isAccessible() === true) {
return $this->parent = $page;
}
if ($this->site->isAccessible() === true) {
return $this->parent = $this->site;
}
throw new PermissionException(
key: 'page.undefined'
);
}
/**

View file

@ -59,8 +59,12 @@ class Lock
}
}
// return the last lock if no lock was found
return $lock;
// no language has an active lock:
// fall back to the lock for the current language,
// so that the user and modification timestamp
// reflect the current version and not the
// arbitrary last-iterated language
return static::for($version, Language::ensure());
}
$language = Language::ensure($language);

View file

@ -56,9 +56,11 @@ class VersionRules
Version $version,
Language $language
): void {
if ($version->isLocked('*') === true) {
$lock = $version->lock('*');
if ($lock->isLocked() === true) {
throw new LockedContentException(
lock: $version->lock('*'),
lock: $lock,
key: 'content.lock.delete'
);
}
@ -74,17 +76,21 @@ class VersionRules
static::ensure($fromVersion, $fromLanguage);
// check if the source version is locked in any language
if ($fromVersion->isLocked('*') === true) {
$fromLock = $fromVersion->lock('*');
if ($fromLock->isLocked() === true) {
throw new LockedContentException(
lock: $fromVersion->lock('*'),
lock: $fromLock,
key: 'content.lock.move'
);
}
// check if the target version is locked in any language
if ($toVersion->isLocked('*') === true) {
$toLock = $toVersion->lock('*');
if ($toLock->isLocked() === true) {
throw new LockedContentException(
lock: $toVersion->lock('*'),
lock: $toLock,
key: 'content.lock.update'
);
}
@ -105,9 +111,11 @@ class VersionRules
static::ensure($version, $language);
// check if the version is locked in any language
if ($version->isLocked('*') === true) {
$lock = $version->lock('*');
if ($lock->isLocked() === true) {
throw new LockedContentException(
lock: $version->lock('*'),
lock: $lock,
key: 'content.lock.publish'
);
}
@ -129,9 +137,11 @@ class VersionRules
static::ensure($version, $language);
// check if the version is locked in any language
if ($version->isLocked('*') === true) {
$lock = $version->lock('*');
if ($lock->isLocked() === true) {
throw new LockedContentException(
lock: $version->lock('*'),
lock: $lock,
key: 'content.lock.replace'
);
}
@ -151,9 +161,11 @@ class VersionRules
): void {
static::ensure($version, $language);
if ($version->isLocked('*') === true) {
$lock = $version->lock('*');
if ($lock->isLocked() === true) {
throw new LockedContentException(
lock: $version->lock('*'),
lock: $lock,
key: 'content.lock.update'
);
}

View file

@ -848,11 +848,25 @@ class Query
// ->where(['username' => 'myuser']);
} elseif (is_array($args[0]) === true) {
// simple array mode (AND operator)
$sql = $this->database->sql()->values($this->table, $args[0], ' AND ', true, true);
$sql = $this->database->sql();
$result = $sql['query'];
// every column in the array must be a valid column;
// otherwise the condition would be silently dropped
// (in Sql::valueSet()) and the clause could collapse to
// nothing, turning a scoped update/delete into a
// full-table operation
foreach (array_keys($args[0]) as $column) {
if ($sql->columnName($this->table, $column) === null) {
throw new InvalidArgumentException(
message: 'Invalid column "' . $column . '" in clause'
);
}
}
$this->bindings($sql['bindings']);
$values = $sql->values($this->table, $args[0], ' AND ', true, true);
$result = $values['query'];
$this->bindings($values['bindings']);
} elseif (is_callable($args[0]) === true) {
$query = clone $this;
@ -906,6 +920,12 @@ class Query
$sql = $this->database->sql();
$key = $sql->columnName($this->table, $args[0]);
if ($key === null) {
throw new InvalidArgumentException(
message: 'Invalid column "' . $args[0] . '" in clause'
);
}
// ->where('username', 'in', ['myuser', 'myotheruser']);
// ->where('quantity', 'between', [10, 50]);
$predicate = trim(strtoupper($args[1]));

View file

@ -19,6 +19,16 @@ class Cookie
{
/**
* Key to use for cookie signing
*
* A hardcoded default is used intentionally: there is no install step
* during which a random key could be generated and persisted. Kirby goes
* live the moment files are present on the server, so there is no defined
* point at which to write a one-time secret. Config files are typically
* kept in version control and cannot be written by the system without
* causing merge conflicts. No value in $_SERVER is both universally
* available across hosting environments and stable enough to serve as a
* key. Sites with security requirements must override this property with
* a secret random value before the first cookie is set.
*/
public static string $key = 'KirbyHttpCookieKey';
@ -157,7 +167,12 @@ class Cookie
*/
protected static function hmac(string $value): string
{
return hash_hmac('sha1', $value, static::$key);
// prefer the option if it was set, otherwise use the value
// set directly to this class (for backwards-compatibility)
// or fall back to the fixed default set directly with the prop
$key = App::instance(lazy: true)?->option('cookie.key') ?: static::$key;
return hash_hmac('sha1', $value, $key);
}
/**

View file

@ -360,8 +360,9 @@ class Environment
// prefer the standardized `Forwarded` header if defined
if ($forwarded = $this->get('HTTP_FORWARDED')) {
// only use the first (outermost) proxy by using the first set of values
// before the first comma (but only a comma outside of quotes)
// only use the first (outermost) proxy by using
// the first set of values before the first comma
// (but only a comma outside of quotes)
if (Str::contains($forwarded, ',') === true) {
$forwarded = preg_split('/"[^"]*"(*SKIP)(*F)|,/', $forwarded)[0];
}
@ -372,6 +373,7 @@ class Environment
// split key and value into an associative array
$fields = [];
foreach ($rawFields as $field) {
$key = Str::lower(Str::before($field, '='));
$value = Str::after($field, '=');
@ -399,7 +401,7 @@ class Environment
$data['port'] ??= 443;
}
$data['for'] = $parts['for'] ?? null;
$data['for'] = $fields['for'] ?? null;
return $data;
}
@ -764,7 +766,9 @@ class Environment
$ips = [
$this->get('REMOTE_ADDR'),
$this->get('HTTP_X_FORWARDED_FOR'),
$this->get('HTTP_CLIENT_IP')
$this->get('HTTP_CLIENT_IP'),
$this->get('HTTP_X_CLIENT_IP'),
$this->get('HTTP_X_REAL_IP'),
];
if ($this->get('HTTP_FORWARDED')) {

View file

@ -189,7 +189,9 @@ class Remote
$value = $key . ': ' . $value;
}
$headers[] = $value;
// Prevent header injection by
// stripping new line characters
$headers[] = str_replace(["\r", "\n"], '', $value);
}
$this->curlopt[CURLOPT_HTTPHEADER] = $headers;

View file

@ -82,9 +82,19 @@ class Focus
// support for former Focus plugin
if (Str::startsWith($value, '{') === true) {
$focus = json_decode($value);
$x = round(100 * $focus->x);
$y = round(100 * $focus->y);
return "$x% $y%";
// ignore malformed/partial JSON
if (
is_object($focus) === true &&
is_numeric($focus->x ?? null) === true &&
is_numeric($focus->y ?? null) === true
) {
$x = round(100 * $focus->x);
$y = round(100 * $focus->y);
return "$x% $y%";
}
return '50% 50%';
}
if (static::isFocalPoint($value) === false) {

View file

@ -85,6 +85,11 @@ class Location implements Stringable
return (float)$parts[0];
}
// guard against forged EXIF with a zero denominator
if ((float)$parts[1] === 0.0) {
return 0.0;
}
return (float)($parts[0]) / (float)($parts[1]);
}

View file

@ -7,6 +7,7 @@ use GdImage;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\LogicException;
use Kirby\Filesystem\F;
use Kirby\Toolkit\Escape;
use Stringable;
/**
@ -152,7 +153,10 @@ class QrCode implements Stringable
fn ($x, $y, $width, $height) => 'M' . $x . ',' . $y . 'h' . $width . 'v' . $height . 'h-' . $width . 'z'
);
$size = $size ? ' style="width: ' . $size . '"' : '';
// escape the values that end up in SVG (XML) attributes
$color = Escape::xml($color);
$back = Escape::xml($back);
$size = $size ? ' style="width: ' . Escape::xml((string)$size) . '"' : '';
return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' . $vbw . ' ' . $vbh . '" stroke="none"' . $size . '>' .
'<rect width="100%" height="100%" fill="' . $back . '"/>' .
@ -1033,6 +1037,14 @@ class QrCode implements Stringable
}
}
// reject data that does not fit into the largest QR version
// instead of overflowing into undefined version/capacity
if ($version > 40) {
throw new InvalidArgumentException(
message: 'The provided data exceeds the maximum capacity of a QR code'
);
}
// with the version in place, try to raise
// the error correction level as long as
// the data still fits

View file

@ -630,14 +630,34 @@ class Dom
*/
public static function unwrap(DOMNode $node): void
{
foreach ($node->childNodes as $childNode) {
// snapshot because `insertBefore` moves children out of `$node`,
// shifting the live `DOMNodeList`
foreach (iterator_to_array($node->childNodes, false) as $childNode) {
// discard text nodes as they can be unexpected
// directly in the parent element
if ($childNode instanceof DOMText) {
continue;
}
$node->parentNode->insertBefore(clone $childNode, $node);
// the child may use a default namespace (`xmlns="…"`)
// that was declared on `$node`; once `$node` is gone,
// libxml would rename it to `<default:child>`, so we
// copy the declaration to the child to suppress it
if (
$childNode instanceof DOMElement &&
($childNode->prefix === '' || $childNode->prefix === null) &&
is_string($childNode->namespaceURI) === true
) {
$childNode->setAttributeNS(
'http://www.w3.org/2000/xmlns/',
'xmlns',
$childNode->namespaceURI
);
}
// move (don't clone) so descendants pending in the
// `Dom::sanitize()` snapshot are still sanitized
$node->parentNode->insertBefore($childNode, $node);
}
static::remove($node);

View file

@ -22,6 +22,18 @@ class Html extends Xml
*/
public static array|null $entities = null;
/**
* List of hosts that are allowed as source for embedded
* Gists. Embedding Gists from any other host is blocked to
* prevent loading untrusted scripts. Additional hosts (e.g.
* for GitHub Enterprise) can be allowed via config:
*
* ```php
* Html::$gistDomains[] = 'gist.example.com';
* ```
*/
public static array $gistDomains = ['gist.github.com'];
/**
* List of HTML tags that can be used inline
*/
@ -303,6 +315,12 @@ class Html extends Xml
string|null $file = null,
array $attr = []
): string {
// only embed Gists from allowed hosts to prevent
// loading untrusted scripts from arbitrary URLs
if (in_array((new Uri($url))->host(), static::$gistDomains, true) === false) {
return '';
}
$src = $url . '.js';
if ($file !== null) {

View file

@ -133,14 +133,16 @@ class Totp
// from user input to increase UX
$totp = preg_replace('/[^0-9]/', '', $totp);
// also allow the previous and upcoming codes
// to account for time sync issues
// also allow the previous and upcoming codes to
// account for time sync issues. Accumulate via OR
// without short-circuiting so the total time does
// not leak which window matched.
$matched = 0;
foreach ([0, -1, 1] as $offset) {
if (hash_equals($this->generate($offset), $totp) === true) {
return true;
}
$matched |= (int)hash_equals($this->generate($offset), $totp);
}
return false;
return $matched === 1;
}
}

View file

@ -1,508 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Base32\\Base32' => $vendorDir . '/christian-riesen/base32/src/Base32.php',
'Base32\\Base32Hex' => $vendorDir . '/christian-riesen/base32/src/Base32Hex.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php',
'Composer\\Semver\\CompilingMatcher' => $vendorDir . '/composer/semver/src/CompilingMatcher.php',
'Composer\\Semver\\Constraint\\Bound' => $vendorDir . '/composer/semver/src/Constraint/Bound.php',
'Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php',
'Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php',
'Composer\\Semver\\Constraint\\MatchAllConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchAllConstraint.php',
'Composer\\Semver\\Constraint\\MatchNoneConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
'Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php',
'Composer\\Semver\\Interval' => $vendorDir . '/composer/semver/src/Interval.php',
'Composer\\Semver\\Intervals' => $vendorDir . '/composer/semver/src/Intervals.php',
'Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php',
'Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php',
'Kirby\\Api\\Api' => $baseDir . '/src/Api/Api.php',
'Kirby\\Api\\Collection' => $baseDir . '/src/Api/Collection.php',
'Kirby\\Api\\Controller\\Changes' => $baseDir . '/src/Api/Controller/Changes.php',
'Kirby\\Api\\Model' => $baseDir . '/src/Api/Model.php',
'Kirby\\Api\\Upload' => $baseDir . '/src/Api/Upload.php',
'Kirby\\Cache\\ApcuCache' => $baseDir . '/src/Cache/ApcuCache.php',
'Kirby\\Cache\\Cache' => $baseDir . '/src/Cache/Cache.php',
'Kirby\\Cache\\FileCache' => $baseDir . '/src/Cache/FileCache.php',
'Kirby\\Cache\\MemCached' => $baseDir . '/src/Cache/MemCached.php',
'Kirby\\Cache\\MemoryCache' => $baseDir . '/src/Cache/MemoryCache.php',
'Kirby\\Cache\\NullCache' => $baseDir . '/src/Cache/NullCache.php',
'Kirby\\Cache\\RedisCache' => $baseDir . '/src/Cache/RedisCache.php',
'Kirby\\Cache\\Value' => $baseDir . '/src/Cache/Value.php',
'Kirby\\Cms\\Api' => $baseDir . '/src/Cms/Api.php',
'Kirby\\Cms\\App' => $baseDir . '/src/Cms/App.php',
'Kirby\\Cms\\AppCaches' => $baseDir . '/src/Cms/AppCaches.php',
'Kirby\\Cms\\AppErrors' => $baseDir . '/src/Cms/AppErrors.php',
'Kirby\\Cms\\AppPlugins' => $baseDir . '/src/Cms/AppPlugins.php',
'Kirby\\Cms\\AppTranslations' => $baseDir . '/src/Cms/AppTranslations.php',
'Kirby\\Cms\\AppUsers' => $baseDir . '/src/Cms/AppUsers.php',
'Kirby\\Cms\\Auth' => $baseDir . '/src/Cms/Auth.php',
'Kirby\\Cms\\Auth\\Challenge' => $baseDir . '/src/Cms/Auth/Challenge.php',
'Kirby\\Cms\\Auth\\EmailChallenge' => $baseDir . '/src/Cms/Auth/EmailChallenge.php',
'Kirby\\Cms\\Auth\\Status' => $baseDir . '/src/Cms/Auth/Status.php',
'Kirby\\Cms\\Auth\\TotpChallenge' => $baseDir . '/src/Cms/Auth/TotpChallenge.php',
'Kirby\\Cms\\Block' => $baseDir . '/src/Cms/Block.php',
'Kirby\\Cms\\BlockConverter' => $baseDir . '/src/Cms/BlockConverter.php',
'Kirby\\Cms\\Blocks' => $baseDir . '/src/Cms/Blocks.php',
'Kirby\\Cms\\Blueprint' => $baseDir . '/src/Cms/Blueprint.php',
'Kirby\\Cms\\Collection' => $baseDir . '/src/Cms/Collection.php',
'Kirby\\Cms\\Collections' => $baseDir . '/src/Cms/Collections.php',
'Kirby\\Cms\\Core' => $baseDir . '/src/Cms/Core.php',
'Kirby\\Cms\\Cors' => $baseDir . '/src/Cms/Cors.php',
'Kirby\\Cms\\Email' => $baseDir . '/src/Cms/Email.php',
'Kirby\\Cms\\Event' => $baseDir . '/src/Cms/Event.php',
'Kirby\\Cms\\Events' => $baseDir . '/src/Cms/Events.php',
'Kirby\\Cms\\Fieldset' => $baseDir . '/src/Cms/Fieldset.php',
'Kirby\\Cms\\Fieldsets' => $baseDir . '/src/Cms/Fieldsets.php',
'Kirby\\Cms\\File' => $baseDir . '/src/Cms/File.php',
'Kirby\\Cms\\FileActions' => $baseDir . '/src/Cms/FileActions.php',
'Kirby\\Cms\\FileBlueprint' => $baseDir . '/src/Cms/FileBlueprint.php',
'Kirby\\Cms\\FileModifications' => $baseDir . '/src/Cms/FileModifications.php',
'Kirby\\Cms\\FilePermissions' => $baseDir . '/src/Cms/FilePermissions.php',
'Kirby\\Cms\\FilePicker' => $baseDir . '/src/Cms/FilePicker.php',
'Kirby\\Cms\\FileRules' => $baseDir . '/src/Cms/FileRules.php',
'Kirby\\Cms\\FileVersion' => $baseDir . '/src/Cms/FileVersion.php',
'Kirby\\Cms\\Files' => $baseDir . '/src/Cms/Files.php',
'Kirby\\Cms\\Find' => $baseDir . '/src/Cms/Find.php',
'Kirby\\Cms\\HasChildren' => $baseDir . '/src/Cms/HasChildren.php',
'Kirby\\Cms\\HasFiles' => $baseDir . '/src/Cms/HasFiles.php',
'Kirby\\Cms\\HasMethods' => $baseDir . '/src/Cms/HasMethods.php',
'Kirby\\Cms\\HasModels' => $baseDir . '/src/Cms/HasModels.php',
'Kirby\\Cms\\HasSiblings' => $baseDir . '/src/Cms/HasSiblings.php',
'Kirby\\Cms\\Helpers' => $baseDir . '/src/Cms/Helpers.php',
'Kirby\\Cms\\Html' => $baseDir . '/src/Cms/Html.php',
'Kirby\\Cms\\Ingredients' => $baseDir . '/src/Cms/Ingredients.php',
'Kirby\\Cms\\Item' => $baseDir . '/src/Cms/Item.php',
'Kirby\\Cms\\Items' => $baseDir . '/src/Cms/Items.php',
'Kirby\\Cms\\Language' => $baseDir . '/src/Cms/Language.php',
'Kirby\\Cms\\LanguagePermissions' => $baseDir . '/src/Cms/LanguagePermissions.php',
'Kirby\\Cms\\LanguageRouter' => $baseDir . '/src/Cms/LanguageRouter.php',
'Kirby\\Cms\\LanguageRoutes' => $baseDir . '/src/Cms/LanguageRoutes.php',
'Kirby\\Cms\\LanguageRules' => $baseDir . '/src/Cms/LanguageRules.php',
'Kirby\\Cms\\LanguageVariable' => $baseDir . '/src/Cms/LanguageVariable.php',
'Kirby\\Cms\\Languages' => $baseDir . '/src/Cms/Languages.php',
'Kirby\\Cms\\Layout' => $baseDir . '/src/Cms/Layout.php',
'Kirby\\Cms\\LayoutColumn' => $baseDir . '/src/Cms/LayoutColumn.php',
'Kirby\\Cms\\LayoutColumns' => $baseDir . '/src/Cms/LayoutColumns.php',
'Kirby\\Cms\\Layouts' => $baseDir . '/src/Cms/Layouts.php',
'Kirby\\Cms\\LazyCollection' => $baseDir . '/src/Cms/LazyCollection.php',
'Kirby\\Cms\\License' => $baseDir . '/src/Cms/License.php',
'Kirby\\Cms\\LicenseStatus' => $baseDir . '/src/Cms/LicenseStatus.php',
'Kirby\\Cms\\LicenseType' => $baseDir . '/src/Cms/LicenseType.php',
'Kirby\\Cms\\Loader' => $baseDir . '/src/Cms/Loader.php',
'Kirby\\Cms\\Media' => $baseDir . '/src/Cms/Media.php',
'Kirby\\Cms\\ModelCommit' => $baseDir . '/src/Cms/ModelCommit.php',
'Kirby\\Cms\\ModelPermissions' => $baseDir . '/src/Cms/ModelPermissions.php',
'Kirby\\Cms\\ModelState' => $baseDir . '/src/Cms/ModelState.php',
'Kirby\\Cms\\ModelWithContent' => $baseDir . '/src/Cms/ModelWithContent.php',
'Kirby\\Cms\\Nest' => $baseDir . '/src/Cms/Nest.php',
'Kirby\\Cms\\NestCollection' => $baseDir . '/src/Cms/NestCollection.php',
'Kirby\\Cms\\NestObject' => $baseDir . '/src/Cms/NestObject.php',
'Kirby\\Cms\\Page' => $baseDir . '/src/Cms/Page.php',
'Kirby\\Cms\\PageActions' => $baseDir . '/src/Cms/PageActions.php',
'Kirby\\Cms\\PageBlueprint' => $baseDir . '/src/Cms/PageBlueprint.php',
'Kirby\\Cms\\PageCopy' => $baseDir . '/src/Cms/PageCopy.php',
'Kirby\\Cms\\PagePermissions' => $baseDir . '/src/Cms/PagePermissions.php',
'Kirby\\Cms\\PagePicker' => $baseDir . '/src/Cms/PagePicker.php',
'Kirby\\Cms\\PageRules' => $baseDir . '/src/Cms/PageRules.php',
'Kirby\\Cms\\PageSiblings' => $baseDir . '/src/Cms/PageSiblings.php',
'Kirby\\Cms\\Pages' => $baseDir . '/src/Cms/Pages.php',
'Kirby\\Cms\\Pagination' => $baseDir . '/src/Cms/Pagination.php',
'Kirby\\Cms\\Permissions' => $baseDir . '/src/Cms/Permissions.php',
'Kirby\\Cms\\Picker' => $baseDir . '/src/Cms/Picker.php',
'Kirby\\Cms\\R' => $baseDir . '/src/Cms/R.php',
'Kirby\\Cms\\Responder' => $baseDir . '/src/Cms/Responder.php',
'Kirby\\Cms\\Response' => $baseDir . '/src/Cms/Response.php',
'Kirby\\Cms\\Role' => $baseDir . '/src/Cms/Role.php',
'Kirby\\Cms\\Roles' => $baseDir . '/src/Cms/Roles.php',
'Kirby\\Cms\\S' => $baseDir . '/src/Cms/S.php',
'Kirby\\Cms\\Search' => $baseDir . '/src/Cms/Search.php',
'Kirby\\Cms\\Section' => $baseDir . '/src/Cms/Section.php',
'Kirby\\Cms\\Site' => $baseDir . '/src/Cms/Site.php',
'Kirby\\Cms\\SiteActions' => $baseDir . '/src/Cms/SiteActions.php',
'Kirby\\Cms\\SiteBlueprint' => $baseDir . '/src/Cms/SiteBlueprint.php',
'Kirby\\Cms\\SitePermissions' => $baseDir . '/src/Cms/SitePermissions.php',
'Kirby\\Cms\\SiteRules' => $baseDir . '/src/Cms/SiteRules.php',
'Kirby\\Cms\\Structure' => $baseDir . '/src/Cms/Structure.php',
'Kirby\\Cms\\StructureObject' => $baseDir . '/src/Cms/StructureObject.php',
'Kirby\\Cms\\System' => $baseDir . '/src/Cms/System.php',
'Kirby\\Cms\\System\\UpdateStatus' => $baseDir . '/src/Cms/System/UpdateStatus.php',
'Kirby\\Cms\\Translation' => $baseDir . '/src/Cms/Translation.php',
'Kirby\\Cms\\Translations' => $baseDir . '/src/Cms/Translations.php',
'Kirby\\Cms\\Url' => $baseDir . '/src/Cms/Url.php',
'Kirby\\Cms\\User' => $baseDir . '/src/Cms/User.php',
'Kirby\\Cms\\UserActions' => $baseDir . '/src/Cms/UserActions.php',
'Kirby\\Cms\\UserBlueprint' => $baseDir . '/src/Cms/UserBlueprint.php',
'Kirby\\Cms\\UserPermissions' => $baseDir . '/src/Cms/UserPermissions.php',
'Kirby\\Cms\\UserPicker' => $baseDir . '/src/Cms/UserPicker.php',
'Kirby\\Cms\\UserRules' => $baseDir . '/src/Cms/UserRules.php',
'Kirby\\Cms\\Users' => $baseDir . '/src/Cms/Users.php',
'Kirby\\Cms\\Visitor' => $baseDir . '/src/Cms/Visitor.php',
'Kirby\\ComposerInstaller\\CmsInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php',
'Kirby\\ComposerInstaller\\Installer' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php',
'Kirby\\ComposerInstaller\\Plugin' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php',
'Kirby\\ComposerInstaller\\PluginInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php',
'Kirby\\Content\\Changes' => $baseDir . '/src/Content/Changes.php',
'Kirby\\Content\\Content' => $baseDir . '/src/Content/Content.php',
'Kirby\\Content\\Field' => $baseDir . '/src/Content/Field.php',
'Kirby\\Content\\ImmutableMemoryStorage' => $baseDir . '/src/Content/ImmutableMemoryStorage.php',
'Kirby\\Content\\Lock' => $baseDir . '/src/Content/Lock.php',
'Kirby\\Content\\LockedContentException' => $baseDir . '/src/Content/LockedContentException.php',
'Kirby\\Content\\MemoryStorage' => $baseDir . '/src/Content/MemoryStorage.php',
'Kirby\\Content\\PlainTextStorage' => $baseDir . '/src/Content/PlainTextStorage.php',
'Kirby\\Content\\Storage' => $baseDir . '/src/Content/Storage.php',
'Kirby\\Content\\Translation' => $baseDir . '/src/Content/Translation.php',
'Kirby\\Content\\Translations' => $baseDir . '/src/Content/Translations.php',
'Kirby\\Content\\Version' => $baseDir . '/src/Content/Version.php',
'Kirby\\Content\\VersionCache' => $baseDir . '/src/Content/VersionCache.php',
'Kirby\\Content\\VersionId' => $baseDir . '/src/Content/VersionId.php',
'Kirby\\Content\\VersionRules' => $baseDir . '/src/Content/VersionRules.php',
'Kirby\\Content\\Versions' => $baseDir . '/src/Content/Versions.php',
'Kirby\\Data\\Data' => $baseDir . '/src/Data/Data.php',
'Kirby\\Data\\Handler' => $baseDir . '/src/Data/Handler.php',
'Kirby\\Data\\Json' => $baseDir . '/src/Data/Json.php',
'Kirby\\Data\\PHP' => $baseDir . '/src/Data/PHP.php',
'Kirby\\Data\\Txt' => $baseDir . '/src/Data/Txt.php',
'Kirby\\Data\\Xml' => $baseDir . '/src/Data/Xml.php',
'Kirby\\Data\\Yaml' => $baseDir . '/src/Data/Yaml.php',
'Kirby\\Data\\YamlSpyc' => $baseDir . '/src/Data/YamlSpyc.php',
'Kirby\\Data\\YamlSymfony' => $baseDir . '/src/Data/YamlSymfony.php',
'Kirby\\Database\\Database' => $baseDir . '/src/Database/Database.php',
'Kirby\\Database\\Db' => $baseDir . '/src/Database/Db.php',
'Kirby\\Database\\Query' => $baseDir . '/src/Database/Query.php',
'Kirby\\Database\\Sql' => $baseDir . '/src/Database/Sql.php',
'Kirby\\Database\\Sql\\Mysql' => $baseDir . '/src/Database/Sql/Mysql.php',
'Kirby\\Database\\Sql\\Sqlite' => $baseDir . '/src/Database/Sql/Sqlite.php',
'Kirby\\Email\\Body' => $baseDir . '/src/Email/Body.php',
'Kirby\\Email\\Email' => $baseDir . '/src/Email/Email.php',
'Kirby\\Email\\PHPMailer' => $baseDir . '/src/Email/PHPMailer.php',
'Kirby\\Exception\\AuthException' => $baseDir . '/src/Exception/AuthException.php',
'Kirby\\Exception\\BadMethodCallException' => $baseDir . '/src/Exception/BadMethodCallException.php',
'Kirby\\Exception\\DuplicateException' => $baseDir . '/src/Exception/DuplicateException.php',
'Kirby\\Exception\\ErrorPageException' => $baseDir . '/src/Exception/ErrorPageException.php',
'Kirby\\Exception\\Exception' => $baseDir . '/src/Exception/Exception.php',
'Kirby\\Exception\\InvalidArgumentException' => $baseDir . '/src/Exception/InvalidArgumentException.php',
'Kirby\\Exception\\LogicException' => $baseDir . '/src/Exception/LogicException.php',
'Kirby\\Exception\\NotFoundException' => $baseDir . '/src/Exception/NotFoundException.php',
'Kirby\\Exception\\PermissionException' => $baseDir . '/src/Exception/PermissionException.php',
'Kirby\\Field\\FieldOptions' => $baseDir . '/src/Field/FieldOptions.php',
'Kirby\\Filesystem\\Asset' => $baseDir . '/src/Filesystem/Asset.php',
'Kirby\\Filesystem\\Dir' => $baseDir . '/src/Filesystem/Dir.php',
'Kirby\\Filesystem\\F' => $baseDir . '/src/Filesystem/F.php',
'Kirby\\Filesystem\\File' => $baseDir . '/src/Filesystem/File.php',
'Kirby\\Filesystem\\Filename' => $baseDir . '/src/Filesystem/Filename.php',
'Kirby\\Filesystem\\IsFile' => $baseDir . '/src/Filesystem/IsFile.php',
'Kirby\\Filesystem\\Mime' => $baseDir . '/src/Filesystem/Mime.php',
'Kirby\\Form\\Field' => $baseDir . '/src/Form/Field.php',
'Kirby\\Form\\FieldClass' => $baseDir . '/src/Form/FieldClass.php',
'Kirby\\Form\\Field\\BlocksField' => $baseDir . '/src/Form/Field/BlocksField.php',
'Kirby\\Form\\Field\\EntriesField' => $baseDir . '/src/Form/Field/EntriesField.php',
'Kirby\\Form\\Field\\LayoutField' => $baseDir . '/src/Form/Field/LayoutField.php',
'Kirby\\Form\\Field\\StatsField' => $baseDir . '/src/Form/Field/StatsField.php',
'Kirby\\Form\\Fields' => $baseDir . '/src/Form/Fields.php',
'Kirby\\Form\\Form' => $baseDir . '/src/Form/Form.php',
'Kirby\\Form\\Mixin\\After' => $baseDir . '/src/Form/Mixin/After.php',
'Kirby\\Form\\Mixin\\Api' => $baseDir . '/src/Form/Mixin/Api.php',
'Kirby\\Form\\Mixin\\Autofocus' => $baseDir . '/src/Form/Mixin/Autofocus.php',
'Kirby\\Form\\Mixin\\Before' => $baseDir . '/src/Form/Mixin/Before.php',
'Kirby\\Form\\Mixin\\EmptyState' => $baseDir . '/src/Form/Mixin/EmptyState.php',
'Kirby\\Form\\Mixin\\Help' => $baseDir . '/src/Form/Mixin/Help.php',
'Kirby\\Form\\Mixin\\Icon' => $baseDir . '/src/Form/Mixin/Icon.php',
'Kirby\\Form\\Mixin\\Label' => $baseDir . '/src/Form/Mixin/Label.php',
'Kirby\\Form\\Mixin\\Max' => $baseDir . '/src/Form/Mixin/Max.php',
'Kirby\\Form\\Mixin\\Min' => $baseDir . '/src/Form/Mixin/Min.php',
'Kirby\\Form\\Mixin\\Model' => $baseDir . '/src/Form/Mixin/Model.php',
'Kirby\\Form\\Mixin\\Placeholder' => $baseDir . '/src/Form/Mixin/Placeholder.php',
'Kirby\\Form\\Mixin\\Translatable' => $baseDir . '/src/Form/Mixin/Translatable.php',
'Kirby\\Form\\Mixin\\Validation' => $baseDir . '/src/Form/Mixin/Validation.php',
'Kirby\\Form\\Mixin\\Value' => $baseDir . '/src/Form/Mixin/Value.php',
'Kirby\\Form\\Mixin\\When' => $baseDir . '/src/Form/Mixin/When.php',
'Kirby\\Form\\Mixin\\Width' => $baseDir . '/src/Form/Mixin/Width.php',
'Kirby\\Form\\Validations' => $baseDir . '/src/Form/Validations.php',
'Kirby\\Http\\Cookie' => $baseDir . '/src/Http/Cookie.php',
'Kirby\\Http\\Environment' => $baseDir . '/src/Http/Environment.php',
'Kirby\\Http\\Exceptions\\NextRouteException' => $baseDir . '/src/Http/Exceptions/NextRouteException.php',
'Kirby\\Http\\Header' => $baseDir . '/src/Http/Header.php',
'Kirby\\Http\\Idn' => $baseDir . '/src/Http/Idn.php',
'Kirby\\Http\\Params' => $baseDir . '/src/Http/Params.php',
'Kirby\\Http\\Path' => $baseDir . '/src/Http/Path.php',
'Kirby\\Http\\Query' => $baseDir . '/src/Http/Query.php',
'Kirby\\Http\\Range' => $baseDir . '/src/Http/Range.php',
'Kirby\\Http\\Remote' => $baseDir . '/src/Http/Remote.php',
'Kirby\\Http\\Request' => $baseDir . '/src/Http/Request.php',
'Kirby\\Http\\Request\\Auth' => $baseDir . '/src/Http/Request/Auth.php',
'Kirby\\Http\\Request\\Auth\\BasicAuth' => $baseDir . '/src/Http/Request/Auth/BasicAuth.php',
'Kirby\\Http\\Request\\Auth\\BearerAuth' => $baseDir . '/src/Http/Request/Auth/BearerAuth.php',
'Kirby\\Http\\Request\\Auth\\SessionAuth' => $baseDir . '/src/Http/Request/Auth/SessionAuth.php',
'Kirby\\Http\\Request\\Body' => $baseDir . '/src/Http/Request/Body.php',
'Kirby\\Http\\Request\\Data' => $baseDir . '/src/Http/Request/Data.php',
'Kirby\\Http\\Request\\Files' => $baseDir . '/src/Http/Request/Files.php',
'Kirby\\Http\\Request\\Query' => $baseDir . '/src/Http/Request/Query.php',
'Kirby\\Http\\Response' => $baseDir . '/src/Http/Response.php',
'Kirby\\Http\\Route' => $baseDir . '/src/Http/Route.php',
'Kirby\\Http\\Router' => $baseDir . '/src/Http/Router.php',
'Kirby\\Http\\Uri' => $baseDir . '/src/Http/Uri.php',
'Kirby\\Http\\Url' => $baseDir . '/src/Http/Url.php',
'Kirby\\Http\\Visitor' => $baseDir . '/src/Http/Visitor.php',
'Kirby\\Http\\VolatileHeaders' => $baseDir . '/src/Http/VolatileHeaders.php',
'Kirby\\Image\\Camera' => $baseDir . '/src/Image/Camera.php',
'Kirby\\Image\\Darkroom' => $baseDir . '/src/Image/Darkroom.php',
'Kirby\\Image\\Darkroom\\GdLib' => $baseDir . '/src/Image/Darkroom/GdLib.php',
'Kirby\\Image\\Darkroom\\ImageMagick' => $baseDir . '/src/Image/Darkroom/ImageMagick.php',
'Kirby\\Image\\Darkroom\\Imagick' => $baseDir . '/src/Image/Darkroom/Imagick.php',
'Kirby\\Image\\Dimensions' => $baseDir . '/src/Image/Dimensions.php',
'Kirby\\Image\\Exif' => $baseDir . '/src/Image/Exif.php',
'Kirby\\Image\\Focus' => $baseDir . '/src/Image/Focus.php',
'Kirby\\Image\\Gravity' => $baseDir . '/src/Image/Gravity.php',
'Kirby\\Image\\Image' => $baseDir . '/src/Image/Image.php',
'Kirby\\Image\\Location' => $baseDir . '/src/Image/Location.php',
'Kirby\\Image\\QrCode' => $baseDir . '/src/Image/QrCode.php',
'Kirby\\Option\\Option' => $baseDir . '/src/Option/Option.php',
'Kirby\\Option\\Options' => $baseDir . '/src/Option/Options.php',
'Kirby\\Option\\OptionsApi' => $baseDir . '/src/Option/OptionsApi.php',
'Kirby\\Option\\OptionsProvider' => $baseDir . '/src/Option/OptionsProvider.php',
'Kirby\\Option\\OptionsQuery' => $baseDir . '/src/Option/OptionsQuery.php',
'Kirby\\Panel\\Assets' => $baseDir . '/src/Panel/Assets.php',
'Kirby\\Panel\\ChangesDialog' => $baseDir . '/src/Panel/ChangesDialog.php',
'Kirby\\Panel\\Collector\\FilesCollector' => $baseDir . '/src/Panel/Collector/FilesCollector.php',
'Kirby\\Panel\\Collector\\ModelsCollector' => $baseDir . '/src/Panel/Collector/ModelsCollector.php',
'Kirby\\Panel\\Collector\\PagesCollector' => $baseDir . '/src/Panel/Collector/PagesCollector.php',
'Kirby\\Panel\\Collector\\UsersCollector' => $baseDir . '/src/Panel/Collector/UsersCollector.php',
'Kirby\\Panel\\Controller\\PageTree' => $baseDir . '/src/Panel/Controller/PageTree.php',
'Kirby\\Panel\\Controller\\Search' => $baseDir . '/src/Panel/Controller/Search.php',
'Kirby\\Panel\\Dialog' => $baseDir . '/src/Panel/Dialog.php',
'Kirby\\Panel\\Document' => $baseDir . '/src/Panel/Document.php',
'Kirby\\Panel\\Drawer' => $baseDir . '/src/Panel/Drawer.php',
'Kirby\\Panel\\Dropdown' => $baseDir . '/src/Panel/Dropdown.php',
'Kirby\\Panel\\Field' => $baseDir . '/src/Panel/Field.php',
'Kirby\\Panel\\File' => $baseDir . '/src/Panel/File.php',
'Kirby\\Panel\\Home' => $baseDir . '/src/Panel/Home.php',
'Kirby\\Panel\\Json' => $baseDir . '/src/Panel/Json.php',
'Kirby\\Panel\\Lab\\Category' => $baseDir . '/src/Panel/Lab/Category.php',
'Kirby\\Panel\\Lab\\Doc' => $baseDir . '/src/Panel/Lab/Doc.php',
'Kirby\\Panel\\Lab\\Doc\\Argument' => $baseDir . '/src/Panel/Lab/Doc/Argument.php',
'Kirby\\Panel\\Lab\\Doc\\Event' => $baseDir . '/src/Panel/Lab/Doc/Event.php',
'Kirby\\Panel\\Lab\\Doc\\Method' => $baseDir . '/src/Panel/Lab/Doc/Method.php',
'Kirby\\Panel\\Lab\\Doc\\Prop' => $baseDir . '/src/Panel/Lab/Doc/Prop.php',
'Kirby\\Panel\\Lab\\Doc\\Slot' => $baseDir . '/src/Panel/Lab/Doc/Slot.php',
'Kirby\\Panel\\Lab\\Docs' => $baseDir . '/src/Panel/Lab/Docs.php',
'Kirby\\Panel\\Lab\\Example' => $baseDir . '/src/Panel/Lab/Example.php',
'Kirby\\Panel\\Lab\\Responses' => $baseDir . '/src/Panel/Lab/Responses.php',
'Kirby\\Panel\\Lab\\Snippet' => $baseDir . '/src/Panel/Lab/Snippet.php',
'Kirby\\Panel\\Lab\\Template' => $baseDir . '/src/Panel/Lab/Template.php',
'Kirby\\Panel\\Menu' => $baseDir . '/src/Panel/Menu.php',
'Kirby\\Panel\\Model' => $baseDir . '/src/Panel/Model.php',
'Kirby\\Panel\\Page' => $baseDir . '/src/Panel/Page.php',
'Kirby\\Panel\\PageCreateDialog' => $baseDir . '/src/Panel/PageCreateDialog.php',
'Kirby\\Panel\\Panel' => $baseDir . '/src/Panel/Panel.php',
'Kirby\\Panel\\Plugins' => $baseDir . '/src/Panel/Plugins.php',
'Kirby\\Panel\\Redirect' => $baseDir . '/src/Panel/Redirect.php',
'Kirby\\Panel\\Request' => $baseDir . '/src/Panel/Request.php',
'Kirby\\Panel\\Search' => $baseDir . '/src/Panel/Search.php',
'Kirby\\Panel\\Site' => $baseDir . '/src/Panel/Site.php',
'Kirby\\Panel\\Ui\\Button' => $baseDir . '/src/Panel/Ui/Button.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageCreateButton' => $baseDir . '/src/Panel/Ui/Buttons/LanguageCreateButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageDeleteButton' => $baseDir . '/src/Panel/Ui/Buttons/LanguageDeleteButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageSettingsButton' => $baseDir . '/src/Panel/Ui/Buttons/LanguageSettingsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguagesDropdown' => $baseDir . '/src/Panel/Ui/Buttons/LanguagesDropdown.php',
'Kirby\\Panel\\Ui\\Buttons\\OpenButton' => $baseDir . '/src/Panel/Ui/Buttons/OpenButton.php',
'Kirby\\Panel\\Ui\\Buttons\\PageStatusButton' => $baseDir . '/src/Panel/Ui/Buttons/PageStatusButton.php',
'Kirby\\Panel\\Ui\\Buttons\\PreviewButton' => $baseDir . '/src/Panel/Ui/Buttons/PreviewButton.php',
'Kirby\\Panel\\Ui\\Buttons\\SettingsButton' => $baseDir . '/src/Panel/Ui/Buttons/SettingsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\VersionsButton' => $baseDir . '/src/Panel/Ui/Buttons/VersionsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\ViewButton' => $baseDir . '/src/Panel/Ui/Buttons/ViewButton.php',
'Kirby\\Panel\\Ui\\Buttons\\ViewButtons' => $baseDir . '/src/Panel/Ui/Buttons/ViewButtons.php',
'Kirby\\Panel\\Ui\\Component' => $baseDir . '/src/Panel/Ui/Component.php',
'Kirby\\Panel\\Ui\\FilePreview' => $baseDir . '/src/Panel/Ui/FilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\AudioFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/AudioFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\DefaultFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/DefaultFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\ImageFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/ImageFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\PdfFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/PdfFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\VideoFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/VideoFilePreview.php',
'Kirby\\Panel\\Ui\\Item\\FileItem' => $baseDir . '/src/Panel/Ui/Item/FileItem.php',
'Kirby\\Panel\\Ui\\Item\\ModelItem' => $baseDir . '/src/Panel/Ui/Item/ModelItem.php',
'Kirby\\Panel\\Ui\\Item\\PageItem' => $baseDir . '/src/Panel/Ui/Item/PageItem.php',
'Kirby\\Panel\\Ui\\Item\\UserItem' => $baseDir . '/src/Panel/Ui/Item/UserItem.php',
'Kirby\\Panel\\Ui\\Stat' => $baseDir . '/src/Panel/Ui/Stat.php',
'Kirby\\Panel\\Ui\\Stats' => $baseDir . '/src/Panel/Ui/Stats.php',
'Kirby\\Panel\\Ui\\Upload' => $baseDir . '/src/Panel/Ui/Upload.php',
'Kirby\\Panel\\User' => $baseDir . '/src/Panel/User.php',
'Kirby\\Panel\\UserTotpDisableDialog' => $baseDir . '/src/Panel/UserTotpDisableDialog.php',
'Kirby\\Panel\\UserTotpEnableDialog' => $baseDir . '/src/Panel/UserTotpEnableDialog.php',
'Kirby\\Panel\\View' => $baseDir . '/src/Panel/View.php',
'Kirby\\Parsley\\Element' => $baseDir . '/src/Parsley/Element.php',
'Kirby\\Parsley\\Inline' => $baseDir . '/src/Parsley/Inline.php',
'Kirby\\Parsley\\Parsley' => $baseDir . '/src/Parsley/Parsley.php',
'Kirby\\Parsley\\Schema' => $baseDir . '/src/Parsley/Schema.php',
'Kirby\\Parsley\\Schema\\Blocks' => $baseDir . '/src/Parsley/Schema/Blocks.php',
'Kirby\\Parsley\\Schema\\Plain' => $baseDir . '/src/Parsley/Schema/Plain.php',
'Kirby\\Plugin\\Asset' => $baseDir . '/src/Plugin/Asset.php',
'Kirby\\Plugin\\Assets' => $baseDir . '/src/Plugin/Assets.php',
'Kirby\\Plugin\\License' => $baseDir . '/src/Plugin/License.php',
'Kirby\\Plugin\\LicenseStatus' => $baseDir . '/src/Plugin/LicenseStatus.php',
'Kirby\\Plugin\\Plugin' => $baseDir . '/src/Plugin/Plugin.php',
'Kirby\\Query\\AST\\ArgumentListNode' => $baseDir . '/src/Query/AST/ArgumentListNode.php',
'Kirby\\Query\\AST\\ArithmeticNode' => $baseDir . '/src/Query/AST/ArithmeticNode.php',
'Kirby\\Query\\AST\\ArrayListNode' => $baseDir . '/src/Query/AST/ArrayListNode.php',
'Kirby\\Query\\AST\\ClosureNode' => $baseDir . '/src/Query/AST/ClosureNode.php',
'Kirby\\Query\\AST\\CoalesceNode' => $baseDir . '/src/Query/AST/CoalesceNode.php',
'Kirby\\Query\\AST\\ComparisonNode' => $baseDir . '/src/Query/AST/ComparisonNode.php',
'Kirby\\Query\\AST\\GlobalFunctionNode' => $baseDir . '/src/Query/AST/GlobalFunctionNode.php',
'Kirby\\Query\\AST\\LiteralNode' => $baseDir . '/src/Query/AST/LiteralNode.php',
'Kirby\\Query\\AST\\LogicalNode' => $baseDir . '/src/Query/AST/LogicalNode.php',
'Kirby\\Query\\AST\\MemberAccessNode' => $baseDir . '/src/Query/AST/MemberAccessNode.php',
'Kirby\\Query\\AST\\Node' => $baseDir . '/src/Query/AST/Node.php',
'Kirby\\Query\\AST\\TernaryNode' => $baseDir . '/src/Query/AST/TernaryNode.php',
'Kirby\\Query\\AST\\VariableNode' => $baseDir . '/src/Query/AST/VariableNode.php',
'Kirby\\Query\\Argument' => $baseDir . '/src/Query/Argument.php',
'Kirby\\Query\\Arguments' => $baseDir . '/src/Query/Arguments.php',
'Kirby\\Query\\Expression' => $baseDir . '/src/Query/Expression.php',
'Kirby\\Query\\Parser\\Parser' => $baseDir . '/src/Query/Parser/Parser.php',
'Kirby\\Query\\Parser\\Token' => $baseDir . '/src/Query/Parser/Token.php',
'Kirby\\Query\\Parser\\TokenType' => $baseDir . '/src/Query/Parser/TokenType.php',
'Kirby\\Query\\Parser\\Tokenizer' => $baseDir . '/src/Query/Parser/Tokenizer.php',
'Kirby\\Query\\Query' => $baseDir . '/src/Query/Query.php',
'Kirby\\Query\\Runners\\DefaultRunner' => $baseDir . '/src/Query/Runners/DefaultRunner.php',
'Kirby\\Query\\Runners\\Runner' => $baseDir . '/src/Query/Runners/Runner.php',
'Kirby\\Query\\Runners\\Scope' => $baseDir . '/src/Query/Runners/Scope.php',
'Kirby\\Query\\Segment' => $baseDir . '/src/Query/Segment.php',
'Kirby\\Query\\Segments' => $baseDir . '/src/Query/Segments.php',
'Kirby\\Query\\Visitors\\DefaultVisitor' => $baseDir . '/src/Query/Visitors/DefaultVisitor.php',
'Kirby\\Query\\Visitors\\Visitor' => $baseDir . '/src/Query/Visitors/Visitor.php',
'Kirby\\Reflection\\Constructor' => $baseDir . '/src/Reflection/Constructor.php',
'Kirby\\Sane\\DomHandler' => $baseDir . '/src/Sane/DomHandler.php',
'Kirby\\Sane\\Handler' => $baseDir . '/src/Sane/Handler.php',
'Kirby\\Sane\\Html' => $baseDir . '/src/Sane/Html.php',
'Kirby\\Sane\\Sane' => $baseDir . '/src/Sane/Sane.php',
'Kirby\\Sane\\Svg' => $baseDir . '/src/Sane/Svg.php',
'Kirby\\Sane\\Svgz' => $baseDir . '/src/Sane/Svgz.php',
'Kirby\\Sane\\Xml' => $baseDir . '/src/Sane/Xml.php',
'Kirby\\Session\\AutoSession' => $baseDir . '/src/Session/AutoSession.php',
'Kirby\\Session\\FileSessionStore' => $baseDir . '/src/Session/FileSessionStore.php',
'Kirby\\Session\\Session' => $baseDir . '/src/Session/Session.php',
'Kirby\\Session\\SessionData' => $baseDir . '/src/Session/SessionData.php',
'Kirby\\Session\\SessionStore' => $baseDir . '/src/Session/SessionStore.php',
'Kirby\\Session\\Sessions' => $baseDir . '/src/Session/Sessions.php',
'Kirby\\Template\\Slot' => $baseDir . '/src/Template/Slot.php',
'Kirby\\Template\\Slots' => $baseDir . '/src/Template/Slots.php',
'Kirby\\Template\\Snippet' => $baseDir . '/src/Template/Snippet.php',
'Kirby\\Template\\Template' => $baseDir . '/src/Template/Template.php',
'Kirby\\Text\\KirbyTag' => $baseDir . '/src/Text/KirbyTag.php',
'Kirby\\Text\\KirbyTags' => $baseDir . '/src/Text/KirbyTags.php',
'Kirby\\Text\\Markdown' => $baseDir . '/src/Text/Markdown.php',
'Kirby\\Text\\SmartyPants' => $baseDir . '/src/Text/SmartyPants.php',
'Kirby\\Toolkit\\A' => $baseDir . '/src/Toolkit/A.php',
'Kirby\\Toolkit\\BlockCollectionAccess' => $baseDir . '/src/Toolkit/BlockCollectionAccess.php',
'Kirby\\Toolkit\\Collection' => $baseDir . '/src/Toolkit/Collection.php',
'Kirby\\Toolkit\\Component' => $baseDir . '/src/Toolkit/Component.php',
'Kirby\\Toolkit\\Config' => $baseDir . '/src/Toolkit/Config.php',
'Kirby\\Toolkit\\Controller' => $baseDir . '/src/Toolkit/Controller.php',
'Kirby\\Toolkit\\Date' => $baseDir . '/src/Toolkit/Date.php',
'Kirby\\Toolkit\\Dom' => $baseDir . '/src/Toolkit/Dom.php',
'Kirby\\Toolkit\\Escape' => $baseDir . '/src/Toolkit/Escape.php',
'Kirby\\Toolkit\\Facade' => $baseDir . '/src/Toolkit/Facade.php',
'Kirby\\Toolkit\\Html' => $baseDir . '/src/Toolkit/Html.php',
'Kirby\\Toolkit\\I18n' => $baseDir . '/src/Toolkit/I18n.php',
'Kirby\\Toolkit\\Iterator' => $baseDir . '/src/Toolkit/Iterator.php',
'Kirby\\Toolkit\\LazyValue' => $baseDir . '/src/Toolkit/LazyValue.php',
'Kirby\\Toolkit\\Locale' => $baseDir . '/src/Toolkit/Locale.php',
'Kirby\\Toolkit\\Obj' => $baseDir . '/src/Toolkit/Obj.php',
'Kirby\\Toolkit\\Pagination' => $baseDir . '/src/Toolkit/Pagination.php',
'Kirby\\Toolkit\\Silo' => $baseDir . '/src/Toolkit/Silo.php',
'Kirby\\Toolkit\\Str' => $baseDir . '/src/Toolkit/Str.php',
'Kirby\\Toolkit\\SymmetricCrypto' => $baseDir . '/src/Toolkit/SymmetricCrypto.php',
'Kirby\\Toolkit\\Totp' => $baseDir . '/src/Toolkit/Totp.php',
'Kirby\\Toolkit\\Tpl' => $baseDir . '/src/Toolkit/Tpl.php',
'Kirby\\Toolkit\\V' => $baseDir . '/src/Toolkit/V.php',
'Kirby\\Toolkit\\View' => $baseDir . '/src/Toolkit/View.php',
'Kirby\\Toolkit\\Xml' => $baseDir . '/src/Toolkit/Xml.php',
'Kirby\\Uuid\\BlockUuid' => $baseDir . '/src/Uuid/BlockUuid.php',
'Kirby\\Uuid\\FieldUuid' => $baseDir . '/src/Uuid/FieldUuid.php',
'Kirby\\Uuid\\FileUuid' => $baseDir . '/src/Uuid/FileUuid.php',
'Kirby\\Uuid\\HasUuids' => $baseDir . '/src/Uuid/HasUuids.php',
'Kirby\\Uuid\\Identifiable' => $baseDir . '/src/Uuid/Identifiable.php',
'Kirby\\Uuid\\ModelUuid' => $baseDir . '/src/Uuid/ModelUuid.php',
'Kirby\\Uuid\\PageUuid' => $baseDir . '/src/Uuid/PageUuid.php',
'Kirby\\Uuid\\SiteUuid' => $baseDir . '/src/Uuid/SiteUuid.php',
'Kirby\\Uuid\\StructureUuid' => $baseDir . '/src/Uuid/StructureUuid.php',
'Kirby\\Uuid\\Uri' => $baseDir . '/src/Uuid/Uri.php',
'Kirby\\Uuid\\UserUuid' => $baseDir . '/src/Uuid/UserUuid.php',
'Kirby\\Uuid\\Uuid' => $baseDir . '/src/Uuid/Uuid.php',
'Kirby\\Uuid\\Uuids' => $baseDir . '/src/Uuid/Uuids.php',
'Laminas\\Escaper\\Escaper' => $vendorDir . '/laminas/laminas-escaper/src/Escaper.php',
'Laminas\\Escaper\\EscaperInterface' => $vendorDir . '/laminas/laminas-escaper/src/EscaperInterface.php',
'Laminas\\Escaper\\Exception\\ExceptionInterface' => $vendorDir . '/laminas/laminas-escaper/src/Exception/ExceptionInterface.php',
'Laminas\\Escaper\\Exception\\InvalidArgumentException' => $vendorDir . '/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php',
'Laminas\\Escaper\\Exception\\RuntimeException' => $vendorDir . '/laminas/laminas-escaper/src/Exception/RuntimeException.php',
'League\\ColorExtractor\\Color' => $vendorDir . '/league/color-extractor/src/Color.php',
'League\\ColorExtractor\\ColorExtractor' => $vendorDir . '/league/color-extractor/src/ColorExtractor.php',
'League\\ColorExtractor\\Palette' => $vendorDir . '/league/color-extractor/src/Palette.php',
'Michelf\\SmartyPants' => $vendorDir . '/michelf/php-smartypants/Michelf/SmartyPants.php',
'Michelf\\SmartyPantsTypographer' => $vendorDir . '/michelf/php-smartypants/Michelf/SmartyPantsTypographer.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPMailer\\PHPMailer\\DSNConfigurator' => $vendorDir . '/phpmailer/phpmailer/src/DSNConfigurator.php',
'PHPMailer\\PHPMailer\\Exception' => $vendorDir . '/phpmailer/phpmailer/src/Exception.php',
'PHPMailer\\PHPMailer\\OAuth' => $vendorDir . '/phpmailer/phpmailer/src/OAuth.php',
'PHPMailer\\PHPMailer\\OAuthTokenProvider' => $vendorDir . '/phpmailer/phpmailer/src/OAuthTokenProvider.php',
'PHPMailer\\PHPMailer\\PHPMailer' => $vendorDir . '/phpmailer/phpmailer/src/PHPMailer.php',
'PHPMailer\\PHPMailer\\POP3' => $vendorDir . '/phpmailer/phpmailer/src/POP3.php',
'PHPMailer\\PHPMailer\\SMTP' => $vendorDir . '/phpmailer/phpmailer/src/SMTP.php',
'Parsedown' => $baseDir . '/dependencies/parsedown/Parsedown.php',
'ParsedownExtra' => $baseDir . '/dependencies/parsedown-extra/ParsedownExtra.php',
'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/src/AbstractLogger.php',
'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/src/InvalidArgumentException.php',
'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/src/LogLevel.php',
'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/src/LoggerAwareInterface.php',
'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/src/LoggerAwareTrait.php',
'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/src/LoggerInterface.php',
'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/src/LoggerTrait.php',
'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/src/NullLogger.php',
'Spyc' => $baseDir . '/dependencies/spyc/Spyc.php',
'Symfony\\Component\\Yaml\\Command\\LintCommand' => $vendorDir . '/symfony/yaml/Command/LintCommand.php',
'Symfony\\Component\\Yaml\\Dumper' => $vendorDir . '/symfony/yaml/Dumper.php',
'Symfony\\Component\\Yaml\\Escaper' => $vendorDir . '/symfony/yaml/Escaper.php',
'Symfony\\Component\\Yaml\\Exception\\DumpException' => $vendorDir . '/symfony/yaml/Exception/DumpException.php',
'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/yaml/Exception/ExceptionInterface.php',
'Symfony\\Component\\Yaml\\Exception\\ParseException' => $vendorDir . '/symfony/yaml/Exception/ParseException.php',
'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => $vendorDir . '/symfony/yaml/Exception/RuntimeException.php',
'Symfony\\Component\\Yaml\\Inline' => $vendorDir . '/symfony/yaml/Inline.php',
'Symfony\\Component\\Yaml\\Parser' => $vendorDir . '/symfony/yaml/Parser.php',
'Symfony\\Component\\Yaml\\ParserState' => $vendorDir . '/symfony/yaml/ParserState.php',
'Symfony\\Component\\Yaml\\Tag\\TaggedValue' => $vendorDir . '/symfony/yaml/Tag/TaggedValue.php',
'Symfony\\Component\\Yaml\\Unescaper' => $vendorDir . '/symfony/yaml/Unescaper.php',
'Symfony\\Component\\Yaml\\Yaml' => $vendorDir . '/symfony/yaml/Yaml.php',
'Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php',
'Symfony\\Polyfill\\Intl\\Idn\\Idn' => $vendorDir . '/symfony/polyfill-intl-idn/Idn.php',
'Symfony\\Polyfill\\Intl\\Idn\\Info' => $vendorDir . '/symfony/polyfill-intl-idn/Info.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php',
'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php',
'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
'Whoops\\Exception\\ErrorException' => $vendorDir . '/filp/whoops/src/Whoops/Exception/ErrorException.php',
'Whoops\\Exception\\Formatter' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Formatter.php',
'Whoops\\Exception\\Frame' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Frame.php',
'Whoops\\Exception\\FrameCollection' => $vendorDir . '/filp/whoops/src/Whoops/Exception/FrameCollection.php',
'Whoops\\Exception\\Inspector' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Inspector.php',
'Whoops\\Handler\\CallbackHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/CallbackHandler.php',
'Whoops\\Handler\\Handler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/Handler.php',
'Whoops\\Handler\\HandlerInterface' => $vendorDir . '/filp/whoops/src/Whoops/Handler/HandlerInterface.php',
'Whoops\\Handler\\JsonResponseHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php',
'Whoops\\Handler\\PlainTextHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/PlainTextHandler.php',
'Whoops\\Handler\\PrettyPageHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php',
'Whoops\\Handler\\XmlResponseHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php',
'Whoops\\Inspector\\InspectorFactory' => $vendorDir . '/filp/whoops/src/Whoops/Inspector/InspectorFactory.php',
'Whoops\\Inspector\\InspectorFactoryInterface' => $vendorDir . '/filp/whoops/src/Whoops/Inspector/InspectorFactoryInterface.php',
'Whoops\\Inspector\\InspectorInterface' => $vendorDir . '/filp/whoops/src/Whoops/Inspector/InspectorInterface.php',
'Whoops\\Run' => $vendorDir . '/filp/whoops/src/Whoops/Run.php',
'Whoops\\RunInterface' => $vendorDir . '/filp/whoops/src/Whoops/RunInterface.php',
'Whoops\\Util\\HtmlDumperOutput' => $vendorDir . '/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php',
'Whoops\\Util\\Misc' => $vendorDir . '/filp/whoops/src/Whoops/Util/Misc.php',
'Whoops\\Util\\SystemFacade' => $vendorDir . '/filp/whoops/src/Whoops/Util/SystemFacade.php',
'Whoops\\Util\\TemplateHelper' => $vendorDir . '/filp/whoops/src/Whoops/Util/TemplateHelper.php',
'claviska\\SimpleImage' => $vendorDir . '/claviska/simpleimage/src/claviska/SimpleImage.php',
);

View file

@ -1,641 +0,0 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit0bf5c8a9cfa251a218fc581ac888fe35
{
public static $files = array (
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'f864ae44e8154e5ff6f4eec32f46d37f' => __DIR__ . '/../..' . '/config/setup.php',
'87988fc7b1c1f093da22a1a3de972f3a' => __DIR__ . '/../..' . '/config/helpers.php',
);
public static $prefixLengthsPsr4 = array (
'W' =>
array (
'Whoops\\' => 7,
),
'S' =>
array (
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Component\\Yaml\\' => 23,
),
'P' =>
array (
'Psr\\Log\\' => 8,
'PHPMailer\\PHPMailer\\' => 20,
),
'L' =>
array (
'League\\ColorExtractor\\' => 22,
'Laminas\\Escaper\\' => 16,
),
'K' =>
array (
'Kirby\\' => 6,
),
'C' =>
array (
'Composer\\Semver\\' => 16,
),
'B' =>
array (
'Base32\\' => 7,
),
);
public static $prefixDirsPsr4 = array (
'Whoops\\' =>
array (
0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops',
),
'Symfony\\Polyfill\\Mbstring\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
),
'Symfony\\Polyfill\\Intl\\Idn\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
),
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'Symfony\\Component\\Yaml\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/yaml',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/src',
),
'PHPMailer\\PHPMailer\\' =>
array (
0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
),
'League\\ColorExtractor\\' =>
array (
0 => __DIR__ . '/..' . '/league/color-extractor/src',
),
'Laminas\\Escaper\\' =>
array (
0 => __DIR__ . '/..' . '/laminas/laminas-escaper/src',
),
'Kirby\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
1 => __DIR__ . '/..' . '/getkirby/composer-installer/src',
),
'Composer\\Semver\\' =>
array (
0 => __DIR__ . '/..' . '/composer/semver/src',
),
'Base32\\' =>
array (
0 => __DIR__ . '/..' . '/christian-riesen/base32/src',
),
);
public static $prefixesPsr0 = array (
'c' =>
array (
'claviska' =>
array (
0 => __DIR__ . '/..' . '/claviska/simpleimage/src',
),
),
'M' =>
array (
'Michelf' =>
array (
0 => __DIR__ . '/..' . '/michelf/php-smartypants',
),
),
);
public static $classMap = array (
'Base32\\Base32' => __DIR__ . '/..' . '/christian-riesen/base32/src/Base32.php',
'Base32\\Base32Hex' => __DIR__ . '/..' . '/christian-riesen/base32/src/Base32Hex.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Composer\\Semver\\Comparator' => __DIR__ . '/..' . '/composer/semver/src/Comparator.php',
'Composer\\Semver\\CompilingMatcher' => __DIR__ . '/..' . '/composer/semver/src/CompilingMatcher.php',
'Composer\\Semver\\Constraint\\Bound' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Bound.php',
'Composer\\Semver\\Constraint\\Constraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Constraint.php',
'Composer\\Semver\\Constraint\\ConstraintInterface' => __DIR__ . '/..' . '/composer/semver/src/Constraint/ConstraintInterface.php',
'Composer\\Semver\\Constraint\\MatchAllConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchAllConstraint.php',
'Composer\\Semver\\Constraint\\MatchNoneConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
'Composer\\Semver\\Constraint\\MultiConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MultiConstraint.php',
'Composer\\Semver\\Interval' => __DIR__ . '/..' . '/composer/semver/src/Interval.php',
'Composer\\Semver\\Intervals' => __DIR__ . '/..' . '/composer/semver/src/Intervals.php',
'Composer\\Semver\\Semver' => __DIR__ . '/..' . '/composer/semver/src/Semver.php',
'Composer\\Semver\\VersionParser' => __DIR__ . '/..' . '/composer/semver/src/VersionParser.php',
'Kirby\\Api\\Api' => __DIR__ . '/../..' . '/src/Api/Api.php',
'Kirby\\Api\\Collection' => __DIR__ . '/../..' . '/src/Api/Collection.php',
'Kirby\\Api\\Controller\\Changes' => __DIR__ . '/../..' . '/src/Api/Controller/Changes.php',
'Kirby\\Api\\Model' => __DIR__ . '/../..' . '/src/Api/Model.php',
'Kirby\\Api\\Upload' => __DIR__ . '/../..' . '/src/Api/Upload.php',
'Kirby\\Cache\\ApcuCache' => __DIR__ . '/../..' . '/src/Cache/ApcuCache.php',
'Kirby\\Cache\\Cache' => __DIR__ . '/../..' . '/src/Cache/Cache.php',
'Kirby\\Cache\\FileCache' => __DIR__ . '/../..' . '/src/Cache/FileCache.php',
'Kirby\\Cache\\MemCached' => __DIR__ . '/../..' . '/src/Cache/MemCached.php',
'Kirby\\Cache\\MemoryCache' => __DIR__ . '/../..' . '/src/Cache/MemoryCache.php',
'Kirby\\Cache\\NullCache' => __DIR__ . '/../..' . '/src/Cache/NullCache.php',
'Kirby\\Cache\\RedisCache' => __DIR__ . '/../..' . '/src/Cache/RedisCache.php',
'Kirby\\Cache\\Value' => __DIR__ . '/../..' . '/src/Cache/Value.php',
'Kirby\\Cms\\Api' => __DIR__ . '/../..' . '/src/Cms/Api.php',
'Kirby\\Cms\\App' => __DIR__ . '/../..' . '/src/Cms/App.php',
'Kirby\\Cms\\AppCaches' => __DIR__ . '/../..' . '/src/Cms/AppCaches.php',
'Kirby\\Cms\\AppErrors' => __DIR__ . '/../..' . '/src/Cms/AppErrors.php',
'Kirby\\Cms\\AppPlugins' => __DIR__ . '/../..' . '/src/Cms/AppPlugins.php',
'Kirby\\Cms\\AppTranslations' => __DIR__ . '/../..' . '/src/Cms/AppTranslations.php',
'Kirby\\Cms\\AppUsers' => __DIR__ . '/../..' . '/src/Cms/AppUsers.php',
'Kirby\\Cms\\Auth' => __DIR__ . '/../..' . '/src/Cms/Auth.php',
'Kirby\\Cms\\Auth\\Challenge' => __DIR__ . '/../..' . '/src/Cms/Auth/Challenge.php',
'Kirby\\Cms\\Auth\\EmailChallenge' => __DIR__ . '/../..' . '/src/Cms/Auth/EmailChallenge.php',
'Kirby\\Cms\\Auth\\Status' => __DIR__ . '/../..' . '/src/Cms/Auth/Status.php',
'Kirby\\Cms\\Auth\\TotpChallenge' => __DIR__ . '/../..' . '/src/Cms/Auth/TotpChallenge.php',
'Kirby\\Cms\\Block' => __DIR__ . '/../..' . '/src/Cms/Block.php',
'Kirby\\Cms\\BlockConverter' => __DIR__ . '/../..' . '/src/Cms/BlockConverter.php',
'Kirby\\Cms\\Blocks' => __DIR__ . '/../..' . '/src/Cms/Blocks.php',
'Kirby\\Cms\\Blueprint' => __DIR__ . '/../..' . '/src/Cms/Blueprint.php',
'Kirby\\Cms\\Collection' => __DIR__ . '/../..' . '/src/Cms/Collection.php',
'Kirby\\Cms\\Collections' => __DIR__ . '/../..' . '/src/Cms/Collections.php',
'Kirby\\Cms\\Core' => __DIR__ . '/../..' . '/src/Cms/Core.php',
'Kirby\\Cms\\Cors' => __DIR__ . '/../..' . '/src/Cms/Cors.php',
'Kirby\\Cms\\Email' => __DIR__ . '/../..' . '/src/Cms/Email.php',
'Kirby\\Cms\\Event' => __DIR__ . '/../..' . '/src/Cms/Event.php',
'Kirby\\Cms\\Events' => __DIR__ . '/../..' . '/src/Cms/Events.php',
'Kirby\\Cms\\Fieldset' => __DIR__ . '/../..' . '/src/Cms/Fieldset.php',
'Kirby\\Cms\\Fieldsets' => __DIR__ . '/../..' . '/src/Cms/Fieldsets.php',
'Kirby\\Cms\\File' => __DIR__ . '/../..' . '/src/Cms/File.php',
'Kirby\\Cms\\FileActions' => __DIR__ . '/../..' . '/src/Cms/FileActions.php',
'Kirby\\Cms\\FileBlueprint' => __DIR__ . '/../..' . '/src/Cms/FileBlueprint.php',
'Kirby\\Cms\\FileModifications' => __DIR__ . '/../..' . '/src/Cms/FileModifications.php',
'Kirby\\Cms\\FilePermissions' => __DIR__ . '/../..' . '/src/Cms/FilePermissions.php',
'Kirby\\Cms\\FilePicker' => __DIR__ . '/../..' . '/src/Cms/FilePicker.php',
'Kirby\\Cms\\FileRules' => __DIR__ . '/../..' . '/src/Cms/FileRules.php',
'Kirby\\Cms\\FileVersion' => __DIR__ . '/../..' . '/src/Cms/FileVersion.php',
'Kirby\\Cms\\Files' => __DIR__ . '/../..' . '/src/Cms/Files.php',
'Kirby\\Cms\\Find' => __DIR__ . '/../..' . '/src/Cms/Find.php',
'Kirby\\Cms\\HasChildren' => __DIR__ . '/../..' . '/src/Cms/HasChildren.php',
'Kirby\\Cms\\HasFiles' => __DIR__ . '/../..' . '/src/Cms/HasFiles.php',
'Kirby\\Cms\\HasMethods' => __DIR__ . '/../..' . '/src/Cms/HasMethods.php',
'Kirby\\Cms\\HasModels' => __DIR__ . '/../..' . '/src/Cms/HasModels.php',
'Kirby\\Cms\\HasSiblings' => __DIR__ . '/../..' . '/src/Cms/HasSiblings.php',
'Kirby\\Cms\\Helpers' => __DIR__ . '/../..' . '/src/Cms/Helpers.php',
'Kirby\\Cms\\Html' => __DIR__ . '/../..' . '/src/Cms/Html.php',
'Kirby\\Cms\\Ingredients' => __DIR__ . '/../..' . '/src/Cms/Ingredients.php',
'Kirby\\Cms\\Item' => __DIR__ . '/../..' . '/src/Cms/Item.php',
'Kirby\\Cms\\Items' => __DIR__ . '/../..' . '/src/Cms/Items.php',
'Kirby\\Cms\\Language' => __DIR__ . '/../..' . '/src/Cms/Language.php',
'Kirby\\Cms\\LanguagePermissions' => __DIR__ . '/../..' . '/src/Cms/LanguagePermissions.php',
'Kirby\\Cms\\LanguageRouter' => __DIR__ . '/../..' . '/src/Cms/LanguageRouter.php',
'Kirby\\Cms\\LanguageRoutes' => __DIR__ . '/../..' . '/src/Cms/LanguageRoutes.php',
'Kirby\\Cms\\LanguageRules' => __DIR__ . '/../..' . '/src/Cms/LanguageRules.php',
'Kirby\\Cms\\LanguageVariable' => __DIR__ . '/../..' . '/src/Cms/LanguageVariable.php',
'Kirby\\Cms\\Languages' => __DIR__ . '/../..' . '/src/Cms/Languages.php',
'Kirby\\Cms\\Layout' => __DIR__ . '/../..' . '/src/Cms/Layout.php',
'Kirby\\Cms\\LayoutColumn' => __DIR__ . '/../..' . '/src/Cms/LayoutColumn.php',
'Kirby\\Cms\\LayoutColumns' => __DIR__ . '/../..' . '/src/Cms/LayoutColumns.php',
'Kirby\\Cms\\Layouts' => __DIR__ . '/../..' . '/src/Cms/Layouts.php',
'Kirby\\Cms\\LazyCollection' => __DIR__ . '/../..' . '/src/Cms/LazyCollection.php',
'Kirby\\Cms\\License' => __DIR__ . '/../..' . '/src/Cms/License.php',
'Kirby\\Cms\\LicenseStatus' => __DIR__ . '/../..' . '/src/Cms/LicenseStatus.php',
'Kirby\\Cms\\LicenseType' => __DIR__ . '/../..' . '/src/Cms/LicenseType.php',
'Kirby\\Cms\\Loader' => __DIR__ . '/../..' . '/src/Cms/Loader.php',
'Kirby\\Cms\\Media' => __DIR__ . '/../..' . '/src/Cms/Media.php',
'Kirby\\Cms\\ModelCommit' => __DIR__ . '/../..' . '/src/Cms/ModelCommit.php',
'Kirby\\Cms\\ModelPermissions' => __DIR__ . '/../..' . '/src/Cms/ModelPermissions.php',
'Kirby\\Cms\\ModelState' => __DIR__ . '/../..' . '/src/Cms/ModelState.php',
'Kirby\\Cms\\ModelWithContent' => __DIR__ . '/../..' . '/src/Cms/ModelWithContent.php',
'Kirby\\Cms\\Nest' => __DIR__ . '/../..' . '/src/Cms/Nest.php',
'Kirby\\Cms\\NestCollection' => __DIR__ . '/../..' . '/src/Cms/NestCollection.php',
'Kirby\\Cms\\NestObject' => __DIR__ . '/../..' . '/src/Cms/NestObject.php',
'Kirby\\Cms\\Page' => __DIR__ . '/../..' . '/src/Cms/Page.php',
'Kirby\\Cms\\PageActions' => __DIR__ . '/../..' . '/src/Cms/PageActions.php',
'Kirby\\Cms\\PageBlueprint' => __DIR__ . '/../..' . '/src/Cms/PageBlueprint.php',
'Kirby\\Cms\\PageCopy' => __DIR__ . '/../..' . '/src/Cms/PageCopy.php',
'Kirby\\Cms\\PagePermissions' => __DIR__ . '/../..' . '/src/Cms/PagePermissions.php',
'Kirby\\Cms\\PagePicker' => __DIR__ . '/../..' . '/src/Cms/PagePicker.php',
'Kirby\\Cms\\PageRules' => __DIR__ . '/../..' . '/src/Cms/PageRules.php',
'Kirby\\Cms\\PageSiblings' => __DIR__ . '/../..' . '/src/Cms/PageSiblings.php',
'Kirby\\Cms\\Pages' => __DIR__ . '/../..' . '/src/Cms/Pages.php',
'Kirby\\Cms\\Pagination' => __DIR__ . '/../..' . '/src/Cms/Pagination.php',
'Kirby\\Cms\\Permissions' => __DIR__ . '/../..' . '/src/Cms/Permissions.php',
'Kirby\\Cms\\Picker' => __DIR__ . '/../..' . '/src/Cms/Picker.php',
'Kirby\\Cms\\R' => __DIR__ . '/../..' . '/src/Cms/R.php',
'Kirby\\Cms\\Responder' => __DIR__ . '/../..' . '/src/Cms/Responder.php',
'Kirby\\Cms\\Response' => __DIR__ . '/../..' . '/src/Cms/Response.php',
'Kirby\\Cms\\Role' => __DIR__ . '/../..' . '/src/Cms/Role.php',
'Kirby\\Cms\\Roles' => __DIR__ . '/../..' . '/src/Cms/Roles.php',
'Kirby\\Cms\\S' => __DIR__ . '/../..' . '/src/Cms/S.php',
'Kirby\\Cms\\Search' => __DIR__ . '/../..' . '/src/Cms/Search.php',
'Kirby\\Cms\\Section' => __DIR__ . '/../..' . '/src/Cms/Section.php',
'Kirby\\Cms\\Site' => __DIR__ . '/../..' . '/src/Cms/Site.php',
'Kirby\\Cms\\SiteActions' => __DIR__ . '/../..' . '/src/Cms/SiteActions.php',
'Kirby\\Cms\\SiteBlueprint' => __DIR__ . '/../..' . '/src/Cms/SiteBlueprint.php',
'Kirby\\Cms\\SitePermissions' => __DIR__ . '/../..' . '/src/Cms/SitePermissions.php',
'Kirby\\Cms\\SiteRules' => __DIR__ . '/../..' . '/src/Cms/SiteRules.php',
'Kirby\\Cms\\Structure' => __DIR__ . '/../..' . '/src/Cms/Structure.php',
'Kirby\\Cms\\StructureObject' => __DIR__ . '/../..' . '/src/Cms/StructureObject.php',
'Kirby\\Cms\\System' => __DIR__ . '/../..' . '/src/Cms/System.php',
'Kirby\\Cms\\System\\UpdateStatus' => __DIR__ . '/../..' . '/src/Cms/System/UpdateStatus.php',
'Kirby\\Cms\\Translation' => __DIR__ . '/../..' . '/src/Cms/Translation.php',
'Kirby\\Cms\\Translations' => __DIR__ . '/../..' . '/src/Cms/Translations.php',
'Kirby\\Cms\\Url' => __DIR__ . '/../..' . '/src/Cms/Url.php',
'Kirby\\Cms\\User' => __DIR__ . '/../..' . '/src/Cms/User.php',
'Kirby\\Cms\\UserActions' => __DIR__ . '/../..' . '/src/Cms/UserActions.php',
'Kirby\\Cms\\UserBlueprint' => __DIR__ . '/../..' . '/src/Cms/UserBlueprint.php',
'Kirby\\Cms\\UserPermissions' => __DIR__ . '/../..' . '/src/Cms/UserPermissions.php',
'Kirby\\Cms\\UserPicker' => __DIR__ . '/../..' . '/src/Cms/UserPicker.php',
'Kirby\\Cms\\UserRules' => __DIR__ . '/../..' . '/src/Cms/UserRules.php',
'Kirby\\Cms\\Users' => __DIR__ . '/../..' . '/src/Cms/Users.php',
'Kirby\\Cms\\Visitor' => __DIR__ . '/../..' . '/src/Cms/Visitor.php',
'Kirby\\ComposerInstaller\\CmsInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php',
'Kirby\\ComposerInstaller\\Installer' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php',
'Kirby\\ComposerInstaller\\Plugin' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php',
'Kirby\\ComposerInstaller\\PluginInstaller' => __DIR__ . '/..' . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php',
'Kirby\\Content\\Changes' => __DIR__ . '/../..' . '/src/Content/Changes.php',
'Kirby\\Content\\Content' => __DIR__ . '/../..' . '/src/Content/Content.php',
'Kirby\\Content\\Field' => __DIR__ . '/../..' . '/src/Content/Field.php',
'Kirby\\Content\\ImmutableMemoryStorage' => __DIR__ . '/../..' . '/src/Content/ImmutableMemoryStorage.php',
'Kirby\\Content\\Lock' => __DIR__ . '/../..' . '/src/Content/Lock.php',
'Kirby\\Content\\LockedContentException' => __DIR__ . '/../..' . '/src/Content/LockedContentException.php',
'Kirby\\Content\\MemoryStorage' => __DIR__ . '/../..' . '/src/Content/MemoryStorage.php',
'Kirby\\Content\\PlainTextStorage' => __DIR__ . '/../..' . '/src/Content/PlainTextStorage.php',
'Kirby\\Content\\Storage' => __DIR__ . '/../..' . '/src/Content/Storage.php',
'Kirby\\Content\\Translation' => __DIR__ . '/../..' . '/src/Content/Translation.php',
'Kirby\\Content\\Translations' => __DIR__ . '/../..' . '/src/Content/Translations.php',
'Kirby\\Content\\Version' => __DIR__ . '/../..' . '/src/Content/Version.php',
'Kirby\\Content\\VersionCache' => __DIR__ . '/../..' . '/src/Content/VersionCache.php',
'Kirby\\Content\\VersionId' => __DIR__ . '/../..' . '/src/Content/VersionId.php',
'Kirby\\Content\\VersionRules' => __DIR__ . '/../..' . '/src/Content/VersionRules.php',
'Kirby\\Content\\Versions' => __DIR__ . '/../..' . '/src/Content/Versions.php',
'Kirby\\Data\\Data' => __DIR__ . '/../..' . '/src/Data/Data.php',
'Kirby\\Data\\Handler' => __DIR__ . '/../..' . '/src/Data/Handler.php',
'Kirby\\Data\\Json' => __DIR__ . '/../..' . '/src/Data/Json.php',
'Kirby\\Data\\PHP' => __DIR__ . '/../..' . '/src/Data/PHP.php',
'Kirby\\Data\\Txt' => __DIR__ . '/../..' . '/src/Data/Txt.php',
'Kirby\\Data\\Xml' => __DIR__ . '/../..' . '/src/Data/Xml.php',
'Kirby\\Data\\Yaml' => __DIR__ . '/../..' . '/src/Data/Yaml.php',
'Kirby\\Data\\YamlSpyc' => __DIR__ . '/../..' . '/src/Data/YamlSpyc.php',
'Kirby\\Data\\YamlSymfony' => __DIR__ . '/../..' . '/src/Data/YamlSymfony.php',
'Kirby\\Database\\Database' => __DIR__ . '/../..' . '/src/Database/Database.php',
'Kirby\\Database\\Db' => __DIR__ . '/../..' . '/src/Database/Db.php',
'Kirby\\Database\\Query' => __DIR__ . '/../..' . '/src/Database/Query.php',
'Kirby\\Database\\Sql' => __DIR__ . '/../..' . '/src/Database/Sql.php',
'Kirby\\Database\\Sql\\Mysql' => __DIR__ . '/../..' . '/src/Database/Sql/Mysql.php',
'Kirby\\Database\\Sql\\Sqlite' => __DIR__ . '/../..' . '/src/Database/Sql/Sqlite.php',
'Kirby\\Email\\Body' => __DIR__ . '/../..' . '/src/Email/Body.php',
'Kirby\\Email\\Email' => __DIR__ . '/../..' . '/src/Email/Email.php',
'Kirby\\Email\\PHPMailer' => __DIR__ . '/../..' . '/src/Email/PHPMailer.php',
'Kirby\\Exception\\AuthException' => __DIR__ . '/../..' . '/src/Exception/AuthException.php',
'Kirby\\Exception\\BadMethodCallException' => __DIR__ . '/../..' . '/src/Exception/BadMethodCallException.php',
'Kirby\\Exception\\DuplicateException' => __DIR__ . '/../..' . '/src/Exception/DuplicateException.php',
'Kirby\\Exception\\ErrorPageException' => __DIR__ . '/../..' . '/src/Exception/ErrorPageException.php',
'Kirby\\Exception\\Exception' => __DIR__ . '/../..' . '/src/Exception/Exception.php',
'Kirby\\Exception\\InvalidArgumentException' => __DIR__ . '/../..' . '/src/Exception/InvalidArgumentException.php',
'Kirby\\Exception\\LogicException' => __DIR__ . '/../..' . '/src/Exception/LogicException.php',
'Kirby\\Exception\\NotFoundException' => __DIR__ . '/../..' . '/src/Exception/NotFoundException.php',
'Kirby\\Exception\\PermissionException' => __DIR__ . '/../..' . '/src/Exception/PermissionException.php',
'Kirby\\Field\\FieldOptions' => __DIR__ . '/../..' . '/src/Field/FieldOptions.php',
'Kirby\\Filesystem\\Asset' => __DIR__ . '/../..' . '/src/Filesystem/Asset.php',
'Kirby\\Filesystem\\Dir' => __DIR__ . '/../..' . '/src/Filesystem/Dir.php',
'Kirby\\Filesystem\\F' => __DIR__ . '/../..' . '/src/Filesystem/F.php',
'Kirby\\Filesystem\\File' => __DIR__ . '/../..' . '/src/Filesystem/File.php',
'Kirby\\Filesystem\\Filename' => __DIR__ . '/../..' . '/src/Filesystem/Filename.php',
'Kirby\\Filesystem\\IsFile' => __DIR__ . '/../..' . '/src/Filesystem/IsFile.php',
'Kirby\\Filesystem\\Mime' => __DIR__ . '/../..' . '/src/Filesystem/Mime.php',
'Kirby\\Form\\Field' => __DIR__ . '/../..' . '/src/Form/Field.php',
'Kirby\\Form\\FieldClass' => __DIR__ . '/../..' . '/src/Form/FieldClass.php',
'Kirby\\Form\\Field\\BlocksField' => __DIR__ . '/../..' . '/src/Form/Field/BlocksField.php',
'Kirby\\Form\\Field\\EntriesField' => __DIR__ . '/../..' . '/src/Form/Field/EntriesField.php',
'Kirby\\Form\\Field\\LayoutField' => __DIR__ . '/../..' . '/src/Form/Field/LayoutField.php',
'Kirby\\Form\\Field\\StatsField' => __DIR__ . '/../..' . '/src/Form/Field/StatsField.php',
'Kirby\\Form\\Fields' => __DIR__ . '/../..' . '/src/Form/Fields.php',
'Kirby\\Form\\Form' => __DIR__ . '/../..' . '/src/Form/Form.php',
'Kirby\\Form\\Mixin\\After' => __DIR__ . '/../..' . '/src/Form/Mixin/After.php',
'Kirby\\Form\\Mixin\\Api' => __DIR__ . '/../..' . '/src/Form/Mixin/Api.php',
'Kirby\\Form\\Mixin\\Autofocus' => __DIR__ . '/../..' . '/src/Form/Mixin/Autofocus.php',
'Kirby\\Form\\Mixin\\Before' => __DIR__ . '/../..' . '/src/Form/Mixin/Before.php',
'Kirby\\Form\\Mixin\\EmptyState' => __DIR__ . '/../..' . '/src/Form/Mixin/EmptyState.php',
'Kirby\\Form\\Mixin\\Help' => __DIR__ . '/../..' . '/src/Form/Mixin/Help.php',
'Kirby\\Form\\Mixin\\Icon' => __DIR__ . '/../..' . '/src/Form/Mixin/Icon.php',
'Kirby\\Form\\Mixin\\Label' => __DIR__ . '/../..' . '/src/Form/Mixin/Label.php',
'Kirby\\Form\\Mixin\\Max' => __DIR__ . '/../..' . '/src/Form/Mixin/Max.php',
'Kirby\\Form\\Mixin\\Min' => __DIR__ . '/../..' . '/src/Form/Mixin/Min.php',
'Kirby\\Form\\Mixin\\Model' => __DIR__ . '/../..' . '/src/Form/Mixin/Model.php',
'Kirby\\Form\\Mixin\\Placeholder' => __DIR__ . '/../..' . '/src/Form/Mixin/Placeholder.php',
'Kirby\\Form\\Mixin\\Translatable' => __DIR__ . '/../..' . '/src/Form/Mixin/Translatable.php',
'Kirby\\Form\\Mixin\\Validation' => __DIR__ . '/../..' . '/src/Form/Mixin/Validation.php',
'Kirby\\Form\\Mixin\\Value' => __DIR__ . '/../..' . '/src/Form/Mixin/Value.php',
'Kirby\\Form\\Mixin\\When' => __DIR__ . '/../..' . '/src/Form/Mixin/When.php',
'Kirby\\Form\\Mixin\\Width' => __DIR__ . '/../..' . '/src/Form/Mixin/Width.php',
'Kirby\\Form\\Validations' => __DIR__ . '/../..' . '/src/Form/Validations.php',
'Kirby\\Http\\Cookie' => __DIR__ . '/../..' . '/src/Http/Cookie.php',
'Kirby\\Http\\Environment' => __DIR__ . '/../..' . '/src/Http/Environment.php',
'Kirby\\Http\\Exceptions\\NextRouteException' => __DIR__ . '/../..' . '/src/Http/Exceptions/NextRouteException.php',
'Kirby\\Http\\Header' => __DIR__ . '/../..' . '/src/Http/Header.php',
'Kirby\\Http\\Idn' => __DIR__ . '/../..' . '/src/Http/Idn.php',
'Kirby\\Http\\Params' => __DIR__ . '/../..' . '/src/Http/Params.php',
'Kirby\\Http\\Path' => __DIR__ . '/../..' . '/src/Http/Path.php',
'Kirby\\Http\\Query' => __DIR__ . '/../..' . '/src/Http/Query.php',
'Kirby\\Http\\Range' => __DIR__ . '/../..' . '/src/Http/Range.php',
'Kirby\\Http\\Remote' => __DIR__ . '/../..' . '/src/Http/Remote.php',
'Kirby\\Http\\Request' => __DIR__ . '/../..' . '/src/Http/Request.php',
'Kirby\\Http\\Request\\Auth' => __DIR__ . '/../..' . '/src/Http/Request/Auth.php',
'Kirby\\Http\\Request\\Auth\\BasicAuth' => __DIR__ . '/../..' . '/src/Http/Request/Auth/BasicAuth.php',
'Kirby\\Http\\Request\\Auth\\BearerAuth' => __DIR__ . '/../..' . '/src/Http/Request/Auth/BearerAuth.php',
'Kirby\\Http\\Request\\Auth\\SessionAuth' => __DIR__ . '/../..' . '/src/Http/Request/Auth/SessionAuth.php',
'Kirby\\Http\\Request\\Body' => __DIR__ . '/../..' . '/src/Http/Request/Body.php',
'Kirby\\Http\\Request\\Data' => __DIR__ . '/../..' . '/src/Http/Request/Data.php',
'Kirby\\Http\\Request\\Files' => __DIR__ . '/../..' . '/src/Http/Request/Files.php',
'Kirby\\Http\\Request\\Query' => __DIR__ . '/../..' . '/src/Http/Request/Query.php',
'Kirby\\Http\\Response' => __DIR__ . '/../..' . '/src/Http/Response.php',
'Kirby\\Http\\Route' => __DIR__ . '/../..' . '/src/Http/Route.php',
'Kirby\\Http\\Router' => __DIR__ . '/../..' . '/src/Http/Router.php',
'Kirby\\Http\\Uri' => __DIR__ . '/../..' . '/src/Http/Uri.php',
'Kirby\\Http\\Url' => __DIR__ . '/../..' . '/src/Http/Url.php',
'Kirby\\Http\\Visitor' => __DIR__ . '/../..' . '/src/Http/Visitor.php',
'Kirby\\Http\\VolatileHeaders' => __DIR__ . '/../..' . '/src/Http/VolatileHeaders.php',
'Kirby\\Image\\Camera' => __DIR__ . '/../..' . '/src/Image/Camera.php',
'Kirby\\Image\\Darkroom' => __DIR__ . '/../..' . '/src/Image/Darkroom.php',
'Kirby\\Image\\Darkroom\\GdLib' => __DIR__ . '/../..' . '/src/Image/Darkroom/GdLib.php',
'Kirby\\Image\\Darkroom\\ImageMagick' => __DIR__ . '/../..' . '/src/Image/Darkroom/ImageMagick.php',
'Kirby\\Image\\Darkroom\\Imagick' => __DIR__ . '/../..' . '/src/Image/Darkroom/Imagick.php',
'Kirby\\Image\\Dimensions' => __DIR__ . '/../..' . '/src/Image/Dimensions.php',
'Kirby\\Image\\Exif' => __DIR__ . '/../..' . '/src/Image/Exif.php',
'Kirby\\Image\\Focus' => __DIR__ . '/../..' . '/src/Image/Focus.php',
'Kirby\\Image\\Gravity' => __DIR__ . '/../..' . '/src/Image/Gravity.php',
'Kirby\\Image\\Image' => __DIR__ . '/../..' . '/src/Image/Image.php',
'Kirby\\Image\\Location' => __DIR__ . '/../..' . '/src/Image/Location.php',
'Kirby\\Image\\QrCode' => __DIR__ . '/../..' . '/src/Image/QrCode.php',
'Kirby\\Option\\Option' => __DIR__ . '/../..' . '/src/Option/Option.php',
'Kirby\\Option\\Options' => __DIR__ . '/../..' . '/src/Option/Options.php',
'Kirby\\Option\\OptionsApi' => __DIR__ . '/../..' . '/src/Option/OptionsApi.php',
'Kirby\\Option\\OptionsProvider' => __DIR__ . '/../..' . '/src/Option/OptionsProvider.php',
'Kirby\\Option\\OptionsQuery' => __DIR__ . '/../..' . '/src/Option/OptionsQuery.php',
'Kirby\\Panel\\Assets' => __DIR__ . '/../..' . '/src/Panel/Assets.php',
'Kirby\\Panel\\ChangesDialog' => __DIR__ . '/../..' . '/src/Panel/ChangesDialog.php',
'Kirby\\Panel\\Collector\\FilesCollector' => __DIR__ . '/../..' . '/src/Panel/Collector/FilesCollector.php',
'Kirby\\Panel\\Collector\\ModelsCollector' => __DIR__ . '/../..' . '/src/Panel/Collector/ModelsCollector.php',
'Kirby\\Panel\\Collector\\PagesCollector' => __DIR__ . '/../..' . '/src/Panel/Collector/PagesCollector.php',
'Kirby\\Panel\\Collector\\UsersCollector' => __DIR__ . '/../..' . '/src/Panel/Collector/UsersCollector.php',
'Kirby\\Panel\\Controller\\PageTree' => __DIR__ . '/../..' . '/src/Panel/Controller/PageTree.php',
'Kirby\\Panel\\Controller\\Search' => __DIR__ . '/../..' . '/src/Panel/Controller/Search.php',
'Kirby\\Panel\\Dialog' => __DIR__ . '/../..' . '/src/Panel/Dialog.php',
'Kirby\\Panel\\Document' => __DIR__ . '/../..' . '/src/Panel/Document.php',
'Kirby\\Panel\\Drawer' => __DIR__ . '/../..' . '/src/Panel/Drawer.php',
'Kirby\\Panel\\Dropdown' => __DIR__ . '/../..' . '/src/Panel/Dropdown.php',
'Kirby\\Panel\\Field' => __DIR__ . '/../..' . '/src/Panel/Field.php',
'Kirby\\Panel\\File' => __DIR__ . '/../..' . '/src/Panel/File.php',
'Kirby\\Panel\\Home' => __DIR__ . '/../..' . '/src/Panel/Home.php',
'Kirby\\Panel\\Json' => __DIR__ . '/../..' . '/src/Panel/Json.php',
'Kirby\\Panel\\Lab\\Category' => __DIR__ . '/../..' . '/src/Panel/Lab/Category.php',
'Kirby\\Panel\\Lab\\Doc' => __DIR__ . '/../..' . '/src/Panel/Lab/Doc.php',
'Kirby\\Panel\\Lab\\Doc\\Argument' => __DIR__ . '/../..' . '/src/Panel/Lab/Doc/Argument.php',
'Kirby\\Panel\\Lab\\Doc\\Event' => __DIR__ . '/../..' . '/src/Panel/Lab/Doc/Event.php',
'Kirby\\Panel\\Lab\\Doc\\Method' => __DIR__ . '/../..' . '/src/Panel/Lab/Doc/Method.php',
'Kirby\\Panel\\Lab\\Doc\\Prop' => __DIR__ . '/../..' . '/src/Panel/Lab/Doc/Prop.php',
'Kirby\\Panel\\Lab\\Doc\\Slot' => __DIR__ . '/../..' . '/src/Panel/Lab/Doc/Slot.php',
'Kirby\\Panel\\Lab\\Docs' => __DIR__ . '/../..' . '/src/Panel/Lab/Docs.php',
'Kirby\\Panel\\Lab\\Example' => __DIR__ . '/../..' . '/src/Panel/Lab/Example.php',
'Kirby\\Panel\\Lab\\Responses' => __DIR__ . '/../..' . '/src/Panel/Lab/Responses.php',
'Kirby\\Panel\\Lab\\Snippet' => __DIR__ . '/../..' . '/src/Panel/Lab/Snippet.php',
'Kirby\\Panel\\Lab\\Template' => __DIR__ . '/../..' . '/src/Panel/Lab/Template.php',
'Kirby\\Panel\\Menu' => __DIR__ . '/../..' . '/src/Panel/Menu.php',
'Kirby\\Panel\\Model' => __DIR__ . '/../..' . '/src/Panel/Model.php',
'Kirby\\Panel\\Page' => __DIR__ . '/../..' . '/src/Panel/Page.php',
'Kirby\\Panel\\PageCreateDialog' => __DIR__ . '/../..' . '/src/Panel/PageCreateDialog.php',
'Kirby\\Panel\\Panel' => __DIR__ . '/../..' . '/src/Panel/Panel.php',
'Kirby\\Panel\\Plugins' => __DIR__ . '/../..' . '/src/Panel/Plugins.php',
'Kirby\\Panel\\Redirect' => __DIR__ . '/../..' . '/src/Panel/Redirect.php',
'Kirby\\Panel\\Request' => __DIR__ . '/../..' . '/src/Panel/Request.php',
'Kirby\\Panel\\Search' => __DIR__ . '/../..' . '/src/Panel/Search.php',
'Kirby\\Panel\\Site' => __DIR__ . '/../..' . '/src/Panel/Site.php',
'Kirby\\Panel\\Ui\\Button' => __DIR__ . '/../..' . '/src/Panel/Ui/Button.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageCreateButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/LanguageCreateButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageDeleteButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/LanguageDeleteButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageSettingsButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/LanguageSettingsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguagesDropdown' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/LanguagesDropdown.php',
'Kirby\\Panel\\Ui\\Buttons\\OpenButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/OpenButton.php',
'Kirby\\Panel\\Ui\\Buttons\\PageStatusButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/PageStatusButton.php',
'Kirby\\Panel\\Ui\\Buttons\\PreviewButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/PreviewButton.php',
'Kirby\\Panel\\Ui\\Buttons\\SettingsButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/SettingsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\VersionsButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/VersionsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\ViewButton' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/ViewButton.php',
'Kirby\\Panel\\Ui\\Buttons\\ViewButtons' => __DIR__ . '/../..' . '/src/Panel/Ui/Buttons/ViewButtons.php',
'Kirby\\Panel\\Ui\\Component' => __DIR__ . '/../..' . '/src/Panel/Ui/Component.php',
'Kirby\\Panel\\Ui\\FilePreview' => __DIR__ . '/../..' . '/src/Panel/Ui/FilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\AudioFilePreview' => __DIR__ . '/../..' . '/src/Panel/Ui/FilePreviews/AudioFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\DefaultFilePreview' => __DIR__ . '/../..' . '/src/Panel/Ui/FilePreviews/DefaultFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\ImageFilePreview' => __DIR__ . '/../..' . '/src/Panel/Ui/FilePreviews/ImageFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\PdfFilePreview' => __DIR__ . '/../..' . '/src/Panel/Ui/FilePreviews/PdfFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\VideoFilePreview' => __DIR__ . '/../..' . '/src/Panel/Ui/FilePreviews/VideoFilePreview.php',
'Kirby\\Panel\\Ui\\Item\\FileItem' => __DIR__ . '/../..' . '/src/Panel/Ui/Item/FileItem.php',
'Kirby\\Panel\\Ui\\Item\\ModelItem' => __DIR__ . '/../..' . '/src/Panel/Ui/Item/ModelItem.php',
'Kirby\\Panel\\Ui\\Item\\PageItem' => __DIR__ . '/../..' . '/src/Panel/Ui/Item/PageItem.php',
'Kirby\\Panel\\Ui\\Item\\UserItem' => __DIR__ . '/../..' . '/src/Panel/Ui/Item/UserItem.php',
'Kirby\\Panel\\Ui\\Stat' => __DIR__ . '/../..' . '/src/Panel/Ui/Stat.php',
'Kirby\\Panel\\Ui\\Stats' => __DIR__ . '/../..' . '/src/Panel/Ui/Stats.php',
'Kirby\\Panel\\Ui\\Upload' => __DIR__ . '/../..' . '/src/Panel/Ui/Upload.php',
'Kirby\\Panel\\User' => __DIR__ . '/../..' . '/src/Panel/User.php',
'Kirby\\Panel\\UserTotpDisableDialog' => __DIR__ . '/../..' . '/src/Panel/UserTotpDisableDialog.php',
'Kirby\\Panel\\UserTotpEnableDialog' => __DIR__ . '/../..' . '/src/Panel/UserTotpEnableDialog.php',
'Kirby\\Panel\\View' => __DIR__ . '/../..' . '/src/Panel/View.php',
'Kirby\\Parsley\\Element' => __DIR__ . '/../..' . '/src/Parsley/Element.php',
'Kirby\\Parsley\\Inline' => __DIR__ . '/../..' . '/src/Parsley/Inline.php',
'Kirby\\Parsley\\Parsley' => __DIR__ . '/../..' . '/src/Parsley/Parsley.php',
'Kirby\\Parsley\\Schema' => __DIR__ . '/../..' . '/src/Parsley/Schema.php',
'Kirby\\Parsley\\Schema\\Blocks' => __DIR__ . '/../..' . '/src/Parsley/Schema/Blocks.php',
'Kirby\\Parsley\\Schema\\Plain' => __DIR__ . '/../..' . '/src/Parsley/Schema/Plain.php',
'Kirby\\Plugin\\Asset' => __DIR__ . '/../..' . '/src/Plugin/Asset.php',
'Kirby\\Plugin\\Assets' => __DIR__ . '/../..' . '/src/Plugin/Assets.php',
'Kirby\\Plugin\\License' => __DIR__ . '/../..' . '/src/Plugin/License.php',
'Kirby\\Plugin\\LicenseStatus' => __DIR__ . '/../..' . '/src/Plugin/LicenseStatus.php',
'Kirby\\Plugin\\Plugin' => __DIR__ . '/../..' . '/src/Plugin/Plugin.php',
'Kirby\\Query\\AST\\ArgumentListNode' => __DIR__ . '/../..' . '/src/Query/AST/ArgumentListNode.php',
'Kirby\\Query\\AST\\ArithmeticNode' => __DIR__ . '/../..' . '/src/Query/AST/ArithmeticNode.php',
'Kirby\\Query\\AST\\ArrayListNode' => __DIR__ . '/../..' . '/src/Query/AST/ArrayListNode.php',
'Kirby\\Query\\AST\\ClosureNode' => __DIR__ . '/../..' . '/src/Query/AST/ClosureNode.php',
'Kirby\\Query\\AST\\CoalesceNode' => __DIR__ . '/../..' . '/src/Query/AST/CoalesceNode.php',
'Kirby\\Query\\AST\\ComparisonNode' => __DIR__ . '/../..' . '/src/Query/AST/ComparisonNode.php',
'Kirby\\Query\\AST\\GlobalFunctionNode' => __DIR__ . '/../..' . '/src/Query/AST/GlobalFunctionNode.php',
'Kirby\\Query\\AST\\LiteralNode' => __DIR__ . '/../..' . '/src/Query/AST/LiteralNode.php',
'Kirby\\Query\\AST\\LogicalNode' => __DIR__ . '/../..' . '/src/Query/AST/LogicalNode.php',
'Kirby\\Query\\AST\\MemberAccessNode' => __DIR__ . '/../..' . '/src/Query/AST/MemberAccessNode.php',
'Kirby\\Query\\AST\\Node' => __DIR__ . '/../..' . '/src/Query/AST/Node.php',
'Kirby\\Query\\AST\\TernaryNode' => __DIR__ . '/../..' . '/src/Query/AST/TernaryNode.php',
'Kirby\\Query\\AST\\VariableNode' => __DIR__ . '/../..' . '/src/Query/AST/VariableNode.php',
'Kirby\\Query\\Argument' => __DIR__ . '/../..' . '/src/Query/Argument.php',
'Kirby\\Query\\Arguments' => __DIR__ . '/../..' . '/src/Query/Arguments.php',
'Kirby\\Query\\Expression' => __DIR__ . '/../..' . '/src/Query/Expression.php',
'Kirby\\Query\\Parser\\Parser' => __DIR__ . '/../..' . '/src/Query/Parser/Parser.php',
'Kirby\\Query\\Parser\\Token' => __DIR__ . '/../..' . '/src/Query/Parser/Token.php',
'Kirby\\Query\\Parser\\TokenType' => __DIR__ . '/../..' . '/src/Query/Parser/TokenType.php',
'Kirby\\Query\\Parser\\Tokenizer' => __DIR__ . '/../..' . '/src/Query/Parser/Tokenizer.php',
'Kirby\\Query\\Query' => __DIR__ . '/../..' . '/src/Query/Query.php',
'Kirby\\Query\\Runners\\DefaultRunner' => __DIR__ . '/../..' . '/src/Query/Runners/DefaultRunner.php',
'Kirby\\Query\\Runners\\Runner' => __DIR__ . '/../..' . '/src/Query/Runners/Runner.php',
'Kirby\\Query\\Runners\\Scope' => __DIR__ . '/../..' . '/src/Query/Runners/Scope.php',
'Kirby\\Query\\Segment' => __DIR__ . '/../..' . '/src/Query/Segment.php',
'Kirby\\Query\\Segments' => __DIR__ . '/../..' . '/src/Query/Segments.php',
'Kirby\\Query\\Visitors\\DefaultVisitor' => __DIR__ . '/../..' . '/src/Query/Visitors/DefaultVisitor.php',
'Kirby\\Query\\Visitors\\Visitor' => __DIR__ . '/../..' . '/src/Query/Visitors/Visitor.php',
'Kirby\\Reflection\\Constructor' => __DIR__ . '/../..' . '/src/Reflection/Constructor.php',
'Kirby\\Sane\\DomHandler' => __DIR__ . '/../..' . '/src/Sane/DomHandler.php',
'Kirby\\Sane\\Handler' => __DIR__ . '/../..' . '/src/Sane/Handler.php',
'Kirby\\Sane\\Html' => __DIR__ . '/../..' . '/src/Sane/Html.php',
'Kirby\\Sane\\Sane' => __DIR__ . '/../..' . '/src/Sane/Sane.php',
'Kirby\\Sane\\Svg' => __DIR__ . '/../..' . '/src/Sane/Svg.php',
'Kirby\\Sane\\Svgz' => __DIR__ . '/../..' . '/src/Sane/Svgz.php',
'Kirby\\Sane\\Xml' => __DIR__ . '/../..' . '/src/Sane/Xml.php',
'Kirby\\Session\\AutoSession' => __DIR__ . '/../..' . '/src/Session/AutoSession.php',
'Kirby\\Session\\FileSessionStore' => __DIR__ . '/../..' . '/src/Session/FileSessionStore.php',
'Kirby\\Session\\Session' => __DIR__ . '/../..' . '/src/Session/Session.php',
'Kirby\\Session\\SessionData' => __DIR__ . '/../..' . '/src/Session/SessionData.php',
'Kirby\\Session\\SessionStore' => __DIR__ . '/../..' . '/src/Session/SessionStore.php',
'Kirby\\Session\\Sessions' => __DIR__ . '/../..' . '/src/Session/Sessions.php',
'Kirby\\Template\\Slot' => __DIR__ . '/../..' . '/src/Template/Slot.php',
'Kirby\\Template\\Slots' => __DIR__ . '/../..' . '/src/Template/Slots.php',
'Kirby\\Template\\Snippet' => __DIR__ . '/../..' . '/src/Template/Snippet.php',
'Kirby\\Template\\Template' => __DIR__ . '/../..' . '/src/Template/Template.php',
'Kirby\\Text\\KirbyTag' => __DIR__ . '/../..' . '/src/Text/KirbyTag.php',
'Kirby\\Text\\KirbyTags' => __DIR__ . '/../..' . '/src/Text/KirbyTags.php',
'Kirby\\Text\\Markdown' => __DIR__ . '/../..' . '/src/Text/Markdown.php',
'Kirby\\Text\\SmartyPants' => __DIR__ . '/../..' . '/src/Text/SmartyPants.php',
'Kirby\\Toolkit\\A' => __DIR__ . '/../..' . '/src/Toolkit/A.php',
'Kirby\\Toolkit\\BlockCollectionAccess' => __DIR__ . '/../..' . '/src/Toolkit/BlockCollectionAccess.php',
'Kirby\\Toolkit\\Collection' => __DIR__ . '/../..' . '/src/Toolkit/Collection.php',
'Kirby\\Toolkit\\Component' => __DIR__ . '/../..' . '/src/Toolkit/Component.php',
'Kirby\\Toolkit\\Config' => __DIR__ . '/../..' . '/src/Toolkit/Config.php',
'Kirby\\Toolkit\\Controller' => __DIR__ . '/../..' . '/src/Toolkit/Controller.php',
'Kirby\\Toolkit\\Date' => __DIR__ . '/../..' . '/src/Toolkit/Date.php',
'Kirby\\Toolkit\\Dom' => __DIR__ . '/../..' . '/src/Toolkit/Dom.php',
'Kirby\\Toolkit\\Escape' => __DIR__ . '/../..' . '/src/Toolkit/Escape.php',
'Kirby\\Toolkit\\Facade' => __DIR__ . '/../..' . '/src/Toolkit/Facade.php',
'Kirby\\Toolkit\\Html' => __DIR__ . '/../..' . '/src/Toolkit/Html.php',
'Kirby\\Toolkit\\I18n' => __DIR__ . '/../..' . '/src/Toolkit/I18n.php',
'Kirby\\Toolkit\\Iterator' => __DIR__ . '/../..' . '/src/Toolkit/Iterator.php',
'Kirby\\Toolkit\\LazyValue' => __DIR__ . '/../..' . '/src/Toolkit/LazyValue.php',
'Kirby\\Toolkit\\Locale' => __DIR__ . '/../..' . '/src/Toolkit/Locale.php',
'Kirby\\Toolkit\\Obj' => __DIR__ . '/../..' . '/src/Toolkit/Obj.php',
'Kirby\\Toolkit\\Pagination' => __DIR__ . '/../..' . '/src/Toolkit/Pagination.php',
'Kirby\\Toolkit\\Silo' => __DIR__ . '/../..' . '/src/Toolkit/Silo.php',
'Kirby\\Toolkit\\Str' => __DIR__ . '/../..' . '/src/Toolkit/Str.php',
'Kirby\\Toolkit\\SymmetricCrypto' => __DIR__ . '/../..' . '/src/Toolkit/SymmetricCrypto.php',
'Kirby\\Toolkit\\Totp' => __DIR__ . '/../..' . '/src/Toolkit/Totp.php',
'Kirby\\Toolkit\\Tpl' => __DIR__ . '/../..' . '/src/Toolkit/Tpl.php',
'Kirby\\Toolkit\\V' => __DIR__ . '/../..' . '/src/Toolkit/V.php',
'Kirby\\Toolkit\\View' => __DIR__ . '/../..' . '/src/Toolkit/View.php',
'Kirby\\Toolkit\\Xml' => __DIR__ . '/../..' . '/src/Toolkit/Xml.php',
'Kirby\\Uuid\\BlockUuid' => __DIR__ . '/../..' . '/src/Uuid/BlockUuid.php',
'Kirby\\Uuid\\FieldUuid' => __DIR__ . '/../..' . '/src/Uuid/FieldUuid.php',
'Kirby\\Uuid\\FileUuid' => __DIR__ . '/../..' . '/src/Uuid/FileUuid.php',
'Kirby\\Uuid\\HasUuids' => __DIR__ . '/../..' . '/src/Uuid/HasUuids.php',
'Kirby\\Uuid\\Identifiable' => __DIR__ . '/../..' . '/src/Uuid/Identifiable.php',
'Kirby\\Uuid\\ModelUuid' => __DIR__ . '/../..' . '/src/Uuid/ModelUuid.php',
'Kirby\\Uuid\\PageUuid' => __DIR__ . '/../..' . '/src/Uuid/PageUuid.php',
'Kirby\\Uuid\\SiteUuid' => __DIR__ . '/../..' . '/src/Uuid/SiteUuid.php',
'Kirby\\Uuid\\StructureUuid' => __DIR__ . '/../..' . '/src/Uuid/StructureUuid.php',
'Kirby\\Uuid\\Uri' => __DIR__ . '/../..' . '/src/Uuid/Uri.php',
'Kirby\\Uuid\\UserUuid' => __DIR__ . '/../..' . '/src/Uuid/UserUuid.php',
'Kirby\\Uuid\\Uuid' => __DIR__ . '/../..' . '/src/Uuid/Uuid.php',
'Kirby\\Uuid\\Uuids' => __DIR__ . '/../..' . '/src/Uuid/Uuids.php',
'Laminas\\Escaper\\Escaper' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Escaper.php',
'Laminas\\Escaper\\EscaperInterface' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/EscaperInterface.php',
'Laminas\\Escaper\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Exception/ExceptionInterface.php',
'Laminas\\Escaper\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php',
'Laminas\\Escaper\\Exception\\RuntimeException' => __DIR__ . '/..' . '/laminas/laminas-escaper/src/Exception/RuntimeException.php',
'League\\ColorExtractor\\Color' => __DIR__ . '/..' . '/league/color-extractor/src/Color.php',
'League\\ColorExtractor\\ColorExtractor' => __DIR__ . '/..' . '/league/color-extractor/src/ColorExtractor.php',
'League\\ColorExtractor\\Palette' => __DIR__ . '/..' . '/league/color-extractor/src/Palette.php',
'Michelf\\SmartyPants' => __DIR__ . '/..' . '/michelf/php-smartypants/Michelf/SmartyPants.php',
'Michelf\\SmartyPantsTypographer' => __DIR__ . '/..' . '/michelf/php-smartypants/Michelf/SmartyPantsTypographer.php',
'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPMailer\\PHPMailer\\DSNConfigurator' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/DSNConfigurator.php',
'PHPMailer\\PHPMailer\\Exception' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/Exception.php',
'PHPMailer\\PHPMailer\\OAuth' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/OAuth.php',
'PHPMailer\\PHPMailer\\OAuthTokenProvider' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/OAuthTokenProvider.php',
'PHPMailer\\PHPMailer\\PHPMailer' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/PHPMailer.php',
'PHPMailer\\PHPMailer\\POP3' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/POP3.php',
'PHPMailer\\PHPMailer\\SMTP' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/SMTP.php',
'Parsedown' => __DIR__ . '/../..' . '/dependencies/parsedown/Parsedown.php',
'ParsedownExtra' => __DIR__ . '/../..' . '/dependencies/parsedown-extra/ParsedownExtra.php',
'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/src/AbstractLogger.php',
'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/src/InvalidArgumentException.php',
'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/src/LogLevel.php',
'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareInterface.php',
'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareTrait.php',
'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerInterface.php',
'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerTrait.php',
'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/src/NullLogger.php',
'Spyc' => __DIR__ . '/../..' . '/dependencies/spyc/Spyc.php',
'Symfony\\Component\\Yaml\\Command\\LintCommand' => __DIR__ . '/..' . '/symfony/yaml/Command/LintCommand.php',
'Symfony\\Component\\Yaml\\Dumper' => __DIR__ . '/..' . '/symfony/yaml/Dumper.php',
'Symfony\\Component\\Yaml\\Escaper' => __DIR__ . '/..' . '/symfony/yaml/Escaper.php',
'Symfony\\Component\\Yaml\\Exception\\DumpException' => __DIR__ . '/..' . '/symfony/yaml/Exception/DumpException.php',
'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/yaml/Exception/ExceptionInterface.php',
'Symfony\\Component\\Yaml\\Exception\\ParseException' => __DIR__ . '/..' . '/symfony/yaml/Exception/ParseException.php',
'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/yaml/Exception/RuntimeException.php',
'Symfony\\Component\\Yaml\\Inline' => __DIR__ . '/..' . '/symfony/yaml/Inline.php',
'Symfony\\Component\\Yaml\\Parser' => __DIR__ . '/..' . '/symfony/yaml/Parser.php',
'Symfony\\Component\\Yaml\\ParserState' => __DIR__ . '/..' . '/symfony/yaml/ParserState.php',
'Symfony\\Component\\Yaml\\Tag\\TaggedValue' => __DIR__ . '/..' . '/symfony/yaml/Tag/TaggedValue.php',
'Symfony\\Component\\Yaml\\Unescaper' => __DIR__ . '/..' . '/symfony/yaml/Unescaper.php',
'Symfony\\Component\\Yaml\\Yaml' => __DIR__ . '/..' . '/symfony/yaml/Yaml.php',
'Symfony\\Polyfill\\Ctype\\Ctype' => __DIR__ . '/..' . '/symfony/polyfill-ctype/Ctype.php',
'Symfony\\Polyfill\\Intl\\Idn\\Idn' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Idn.php',
'Symfony\\Polyfill\\Intl\\Idn\\Info' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Info.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php',
'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Normalizer.php',
'Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php',
'Whoops\\Exception\\ErrorException' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/ErrorException.php',
'Whoops\\Exception\\Formatter' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/Formatter.php',
'Whoops\\Exception\\Frame' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/Frame.php',
'Whoops\\Exception\\FrameCollection' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/FrameCollection.php',
'Whoops\\Exception\\Inspector' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Exception/Inspector.php',
'Whoops\\Handler\\CallbackHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/CallbackHandler.php',
'Whoops\\Handler\\Handler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/Handler.php',
'Whoops\\Handler\\HandlerInterface' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/HandlerInterface.php',
'Whoops\\Handler\\JsonResponseHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php',
'Whoops\\Handler\\PlainTextHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/PlainTextHandler.php',
'Whoops\\Handler\\PrettyPageHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php',
'Whoops\\Handler\\XmlResponseHandler' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php',
'Whoops\\Inspector\\InspectorFactory' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Inspector/InspectorFactory.php',
'Whoops\\Inspector\\InspectorFactoryInterface' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Inspector/InspectorFactoryInterface.php',
'Whoops\\Inspector\\InspectorInterface' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Inspector/InspectorInterface.php',
'Whoops\\Run' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Run.php',
'Whoops\\RunInterface' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/RunInterface.php',
'Whoops\\Util\\HtmlDumperOutput' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php',
'Whoops\\Util\\Misc' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/Misc.php',
'Whoops\\Util\\SystemFacade' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/SystemFacade.php',
'Whoops\\Util\\TemplateHelper' => __DIR__ . '/..' . '/filp/whoops/src/Whoops/Util/TemplateHelper.php',
'claviska\\SimpleImage' => __DIR__ . '/..' . '/claviska/simpleimage/src/claviska/SimpleImage.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit0bf5c8a9cfa251a218fc581ac888fe35::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit0bf5c8a9cfa251a218fc581ac888fe35::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit0bf5c8a9cfa251a218fc581ac888fe35::$prefixesPsr0;
$loader->classMap = ComposerStaticInit0bf5c8a9cfa251a218fc581ac888fe35::$classMap;
}, null, ClassLoader::class);
}
}

View file

@ -0,0 +1,20 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.php]
indent_size = 4
[*.md,*.txt]
trim_trailing_whitespace = false
insert_final_newline = false
[composer.json]
indent_size = 4

2
site/plugins/meta/.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
/index.js binary
/index.css binary

13
site/plugins/meta/.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: [fabianmichael]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

25
site/plugins/meta/.gitignore vendored Normal file
View file

@ -0,0 +1,25 @@
node_modules
.DS_Store
.php-cs-fixer.cache
# files of Composer dependencies that are not needed for the plugin
/vendor/**/.*
/vendor/**/*.json
/vendor/**/*.txt
/vendor/**/*.md
/vendor/**/*.yml
/vendor/**/*.yaml
/vendor/**/*.xml
/vendor/**/*.dist
/vendor/**/readme.php
/vendor/**/LICENSE
/vendor/**/COPYING
/vendor/**/VERSION
/vendor/**/docs/*
/vendor/**/example/*
/vendor/**/examples/*
/vendor/**/test/*
/vendor/**/tests/*
/vendor/**/php4/*
/vendor/getkirby/composer-installer

View file

@ -0,0 +1,58 @@
<?php
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$rules = [
'@PSR12' => true,
'array_syntax' => ['syntax' => 'short'],
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'no_unused_imports' => true,
'not_operator_with_successor_space' => true,
'trailing_comma_in_multiline' => true,
'phpdoc_scalar' => true,
'unary_operator_spaces' => true,
'binary_operator_spaces' => [
'default' => 'single_space',
'operators' => [
'=>' => null,
],
],
'blank_line_before_statement' => [
'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'],
],
'phpdoc_single_line_var_spacing' => true,
'phpdoc_var_without_name' => true,
'class_attributes_separation' => [
'elements' => [
'method' => 'one',
],
],
'method_argument_space' => [
'on_multiline' => 'ensure_fully_multiline',
'keep_multiple_spaces_after_comma' => true,
],
'single_trait_insert_per_statement' => true,
'strict_comparison' => true,
'new_with_braces' => false,
];
$finder = Finder::create()
->in([
__DIR__,
])
->exclude([
'vendor',
])
->name('*.php')
->notName('*.blade.php')
->ignoreDotFiles(true)
->ignoreVCS(true);
return (new Config())
->setRules($rules)
->setFinder($finder)
->setRiskyAllowed(true)
->setUsingCache(true);

21
site/plugins/meta/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Fabian Michael
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

316
site/plugins/meta/README.md Normal file
View file

@ -0,0 +1,316 @@
# Kirby Meta
⚠️ **Warning:** This plugin is in beta state. Documentation and implementation are still incomplete.
This piece of code handles the generation of meta tags for search engines, social networks,
browsers and beyond.
![Screenshot 2022-01-14 at 09-57-24 Mirin Avos Kitchen](https://user-images.githubusercontent.com/395617/149487743-576e7dca-0f66-41d0-821d-42f3581f5e7f.png)
**Key features:**
- 🔎 All-in-one solution for SEO and social media optimization
- 📱 Support for OpenGraph and Schema.org (JSON-LD) markup
- 🚀 Customizable metadata for auto-generated metadata from page contents
- 💻 Extensive panel UI including social media previews
- 🦊 Easy-to-understand language in the panel, providing a good middle ground between simplicity and extensive control options.
- 🧙‍♂️ Most features can be enabled/disabled in config, panel UI only shows enabled features (thanks to dynamic blueprints)
- 🪝 Hooks for altering the plugin's behavior
- 🌍 All blueprints are fully translatable (*English, German, French and Swedish translations are included*)
**Future plans:**
- ✅ Live-check of metadata with hints in the panel
> This plugin is completely free and published under the MIT license. However, if you are using it in a commercial project and want to help me keep up with maintenance, please consider to **[❤️ sponsor me](https://github.com/sponsors/fabianmichael)** for securing the continued development of the plugin.
## Requirements
- PHP 8.0+
- Kirby 3.6.0+
## How it works
The plugin looks for metadata from a page's content file (e.g. `article.txt`) by
the corresponding key. If the page does not contain the specific field, it looks for a metadata
method on the current page model, which can return an array of metadata for the current page.
If that also fails, it will fall back to default metadata, as stored in the
`site.txt` file at the top-level of the content directory.
That way, every page will always be able to serve default values, even if the specific
page or its model does not contain information like e.g. a thumbnail or a dedicated
description.
## Installation & Setup
**Install using composer (recommended):**
```
composer require fabianmichael/kirby-meta
```
**Alternative download methods:**
You can also download this repository as ZIP or add the whole repo as a submodule.
To run from source, you need to install the dependencies : `composer install`.
### Available configuration options
The options below have to be set in your `config.php`. Please note that every option has to be prefixed with the plugin namespace, e.g. `sitemap` => `fabianmichael.meta.sitemap`.
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `sitemap` | `bool` | `true` | When `true`, will generate an XML sitemap for search engines. The sitemap includes all listed pages by default. ⚠️ If you disable the `robots` setting, no robots.txt will be served to tell search engines where your sitemap is located. |
| `sitemap.detailSettings` | `bool` | `false` | When `true`, the `<changefreq>` and `<priority>` tags are included in the sitemap and their corresponding fields are displayed in the panel. |
| `sitemap.pages.exclude` | `array` | `[]` | An array of page IDs to exlude from the sitemap. Values are treated as regular expressions, so they can include wildcards like e.g. `about/.*`. The error page is always excluded. |
| `sitemap.pages.includeUnlisted` | `array` | `[]` | An array of page IDs to include in the sitemap, even if their status is `unlisted`. Values are treated as regular expressions, so they can include wildcards like e.g. `about/.*`. |
| `sitemap.templates.exclude` | `array` | `[]` | An array of template names to exlude from the sitemap. Values are treated as regular expressions, so they can include wildcards like e.g. `article-(internal|secret)` |
| `sitemap.templates.includeUnlisted` | `array` | `[]` | An array of templates to include in the sitemap, even if their status is `unlisted`. Values are treated as regular expressions. |
| `schema` | `bool` | `true` | Generates [Schema.org](https://schema.org/) markup as [JSON-LD](https://json-ld.org/).
| `social` | `bool` | `true` | Generates [OpenGraph](https://ogp.me/) markup.
| `twitter` | `bool` | `true` | Generates [Twitter Cards](https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards) markup. Only has an effect, if `social` is also enabled. Since `0.2.0-beta` (⚠️ deprecated).
| `robots` | `bool` | `true` | Generates the `robots` metatag and serve [robots.txt](https://developers.google.com/search/docs/advanced/robots/intro) at `http(s)://yourdomain.com/robots.txt`.
| `robots.canonical` | `bool` | `true` | Generates canonical url meta tag. Requires `robots` option to be `true`. |
| `robots.index` | `bool` | `true` | Allows crawlers to index pages. Can be overriden in global or page-specific settings from the panel. Requires `robots` option to be `true` for having an effect. If a page is excluded from the sitemap or unlisted, the robots meta tag will always contain `noindex`. |
| `robots.follow` | `bool` | `true` | Allows crawlers to follow links on pages. Can be overriden in global or page-specific settings from the panel. Requires `robots` option to be `true` for having an effect. |
| `robots.archive` | `bool` | `true` | Allows crawlers to serve a cached version of pages. Can be overriden in global or page-specific settings from the panel. Requires `robots` option to be `true` for having an effect. |
| `robots.imageindex` | `bool` | `true` | Allows crawlers to include images to appear in search results. Can be overriden in global or page-specific settings from the panel. Requires `robots` option to be `true` for having an effect. |
| `robots.snippet` | `bool` | `true` | Allows crawlers to generate snippets from page content. Can be overriden in global or page-specific settings from the panel. Requires `robots` option to be `true` for having an effect. |
| `robots.translate` | `bool` | `true` | Allows crawlers offer automated translation of your content. Can be overriden in global or page-specific settings from the panel. Requires `robots` option to be `true` for having an effect. |
| `robots.forceNoIndex` | `bool` | `false` | This will force-override all robots settings. You will still get a proper preview in the panel and everything will look like normal, but the robots meta tag will always have a content of none. This is useful for staging servers, where users want to edit content like normal, but you want to ensure that pages will not appear in search engines. |
| `title.separators` | `array` | `["~" , "-" , "" , "—" , ":" , "/", …]` | List of available separator options for the `<title>` tag. The separator can be selected in the panel and is placed between page title and site title. |
| `theme.color` | `string\|null` | `null` | If not empty, will generate a corresponding meta tag used by some browsers for coloring the UI. |
| `panel.view.filter` | Provides a filter function for hiding certain pages from the metadata debug view in the panel. See the Kirby docs on [`$pages->filter()`](https://getkirby.com/docs/reference/objects/cms/pages/filter) for details. |
### Blueprint setup
Your site and page blueprints need to use [tabs](https://getkirby.com/docs/guide/blueprints/layout#tabs), as the plugin's input fields all come in a tab. Meta comes with tab blueprints that need to be added to your site and page blueprints accordingly:
```yaml
# site/blueprints/site.yml
[…]
tabs:
structure:
label: Structure
columns:
[…]
meta: tabs/meta/site
# site/blueprints/pages/default.yml
[…]
tabs:
content:
label: Content
columns:
[…]
meta: tabs/meta/page
```
### Template setup
Include the `meta` snippet within your `<head>` element, preferably before
loading any scripts or stylesheets:
```php
<!doctype html>
<html>
<head>
<?php snippet('meta') ?>
[…]
</head>
[…]
```
Now you are ready to add/edit metadata from the panel.
## Advanced usage
### Providing metadata from page models
Sometimes, you want special behavior for certain templates. The easiest way to achieve this is by creating a page model and implementing a `$page->metadata()` method, that returns an array some or even all of the following keys:
| Key | Type | Description |
|:----|:-----|:------------|
| `meta_description` | `string` | Provide a default description that is used, when the user had not entered a dedicated description for this page. This could e.g. be a truncated version of the page's text content. |
| `og_title_prefix` | `string` | Will be put in front of the page's OpenGraph title, e.g. `' '` or `'[Recipe ]` |
| `og_image File` | `Kirby\Cms\File` | A `File` object, that sets the default OpenGraph image for this page. You can even generate custom images programatically and Wrap them in a `File` object, e.g. for the docs of your product (getkirby.com does this for the reference pages).
| `@graph` | `array` | Things to add to the JSON-LD metadata in the page's head. If you need to reference the organization or person behind the website, use `url('/#owner')`. If you need to reference the website itself, use `url('/#website')`. |
| `@social` | `array` | Extend the social meta tags generated by the plugin. |
### Using hooks
the meta plugin provides a set of handy hooks, allowing you to further add/remove/modify metadata without overriding the built-in snippets or having to set up a page model for every template.
⚠️ Hooks are a powerful tool that can break the plugin's expected behavior for editors working on the panel. Use with care!
#### `meta.load:after`
After metadata has been loaded by calling the `$page->metadata()` method on a model. This allows you to inject additional data.
```php
return [
'meta.load:after' => function (
array $metadata,
Kirby\Cms\Page $page,
?string $languageCode
) {
// set `thumbnail.png` as default share image for all pages,
// if not other image was already set by a page model
if (empty($metadata['og_image']) === true) {
$metadata['og_image'] = $page->image('thumbnail.png');
}
return $metadata;
},
];
```
#### `meta.jsonld:after` hook
After the Schema.org graph has been generated. This allows you to pass additional data to the array.
```php
return [
'meta.jsonld:after' => function (
array $json,
FabianMichael\Meta\PageMeta $meta,
Kirby\Cms\Page $page
) {
// add breadcrumb to JSON-LD graph
$items = [];
$parents = $page->parents();
if ($parents->count() === 0) {
return $json;
}
$i = 0;
foreach ($parents->flip() as $parent) {
$items[] = [
'@type' => 'ListItem',
'position' => ++$i,
'item' => [
'@id' => $parent->url(),
'name' => $parent->title()->toString(),
],
];
}
$json['@graph'][] = [
'@type' => 'BreadcrumbList',
'itemListElement' => $items,
];
return $json;
},
];
```
#### `meta.social:after`
Allows you to alter the OpenGraph/Twitter card data.
```php
return [
'meta.social:after' => function (
array $social,
FabianMichael\Meta\PageMeta $meta,
Kirby\Cms\Page $page
) {
// add first video file of page to OpenGraph markup
if ($page->hasVideos()) {
$social[] = [
'property' => 'og:video',
'content' => $page->videos()->first()->url(),
];
}
return $social;
},
];
```
#### `'meta.sitemap…` hooks
These hooks allow you to completely alter the way how the sitemap is being generated. These functions are meant to manipulate the provided DOM document and elements directly and should not return anything.
```php
return [
'hooks' => [
'meta.sitemap:before' => function (
Kirby $kirby,
DOMDocument $doc,
DOMElement $root
) {
// add namespace for image sitemap
$root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:image', 'http://www.google.com/schemas/sitemap-image/1.1');
},
'meta.sitemap.url' => function (
Kirby $kirby,
Page $page,
PageMeta $meta,
DOMDocument $doc,
DOMElement $url) {
if ($page->images()->count() === 0) {
// dynamically exclude page from the sitemap
return false;
}
foreach ($page->images() as $image) {
// add all images from page to image sitemap.
$imageEl = $doc->createElement('image:image');
$imageEl->appendChild($doc->createElement('image:loc', $image->url()));
if ($image->alt()->isNotEmpty()) {
$imageEl->appendChild($doc->createElement('image:caption', $image->alt()));
}
$url->appendChild($imageEl);
}
},
'meta.sitemap:after' => function (
Kirby $kirby,
DOMDocument $doc,
DOMElement $root
) {
foreach ($root->getElementsByTagName('url') as $url) {
if ($lastmod = $url->getElementsByTagName('lastmod')[0] ?? null) {
// remove lastmod date from sitemap entries for some reason …
$url->removeChild($lastmod);
}
}
},
'meta.theme.color' => function (
?string $color
) {
return '#ff0000';
}
],
];
```
### Manipulating indexed pages
A few helpers are available for manipulating pages:
### Page Method
If you'd like to know if a page is indexed in the sitemap, you can use `$page->isIndexible()` (returns a `bool`).
### Site Method
To get all indexed pages according to your settings, you can use : `$site->indexedPages()` (returns a `Kirby\Cms\Collection` of pages).
## Credits
This is partly based on an older version of the meta plugin, that I had initially
developed for [getkirby.com](https://getkirby.com). I liked the idea so much,
that I wanted to adapt it for general use on other websites.
It took a lot of inspiration (and some code) from other existing Kirby plugins,
like [MetaKnight](https://github.com/diesdasdigital/kirby-meta-knight/)
by [diesdas ⚡️ digital](https://www.diesdas.digital/)
and [Meta Tags](https://github.com/pedroborges/kirby-meta-tags)
by [Pedro Borges](https://github.com/pedroborges).

View file

@ -0,0 +1,63 @@
<?php
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby) {
// basic metadata
$fields = [
'meta_general_headline' => [
'type' => 'headline',
'label' => t('fabianmichael.meta.general.headline'),
'numbered' => false,
],
'meta_description' => [
'type' => 'text',
'label' => t('fabianmichael.meta.description.label'),
'placeholder' => '{{ page.meta.get("meta_description", true, true) }}',
'help' => t('fabianmichael.meta.description.help'),
],
'meta_title' => [
'type' => 'text',
'label' => t('fabianmichael.meta.title.label'),
'placeholder' => '{{ page.meta.panelTitlePlaceholder }}',
'help' => t('fabianmichael.meta.title.help'),
],
'meta_title_preview' => [
'type' => 'meta-title-preview',
'label' => t('fabianmichael.meta.title_preview.label'),
],
];
// robots
if ($kirby->option('fabianmichael.meta.robots') !== false && $kirby->option('fabianmichael.meta.robots.canonical') !== false) {
$fields['meta_canonical_url'] = [
'type' => 'url',
'label' => t('fabianmichael.meta.canonical_url.label'),
'placeholder' => '{{ page.url }}',
'help' => t('fabianmichael.meta.canonical_url.help'),
];
}
// sitemap
if ($kirby->option('fabianmichael.meta.sitemap') !== false
&& $kirby->option('fabianmichael.meta.sitemap.detailSettings') !== false) {
$fields['sitemap_priority'] = [
'extends' => 'fields/meta/sitemap-priority',
'width' => '1/2',
];
$fields['sitemap_changefreq'] = [
'extends' => 'fields/meta/sitemap-changefreq',
'width' => '1/2',
];
}
return [
'type' => 'group',
'fields' => $fields,
];
};

View file

@ -0,0 +1,56 @@
<?php
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby) {
// basic metadata
$fields = [
'meta_general_headline' => [
'type' => 'headline',
'label' => t('fabianmichael.meta.global_general.headline'),
'numbered' => false,
],
'meta_description' => [
'type' => 'text',
'label' => t('fabianmichael.meta.description.label'),
'help' => t('fabianmichael.meta.global_description.help'),
],
'meta_title_separator' => [
'type' => 'select',
'label' => t('fabianmichael.meta.title_separator.label'),
'default' => '',
'placeholder' => '|',
'options' => $kirby->option('fabianmichael.meta.title.separators'),
'width' => '1/3',
'help' => t('fabianmichael.meta.title_separator.help'),
],
'meta_title_preview' => [
'type' => 'meta-title-preview',
'label' => 'Preview',
'width' => '2/3',
],
];
// sitemap
if ($kirby->option('fabianmichael.meta.sitemap') !== false
&& $kirby->option('fabianmichael.meta.sitemap.detailSettings') !== false) {
$fields['sitemap_priority'] = [
'extends' => 'fields/meta/sitemap-priority',
'help' => t('fabianmichael.meta.sitemap.global_priority.help'),
'width' => '1/2',
];
$fields['sitemap_changefreq'] = [
'extends' => 'fields/meta/global-sitemap-changefreq',
'width' => '1/2',
];
}
return [
'type' => 'group',
'fields' => $fields,
];
};

View file

@ -0,0 +1,17 @@
type: group
fields:
og_headline:
type: headline
label: fabianmichael.meta.og.headline
numbered: false
help: fabianmichael.meta.og.help
og_site_name:
type: text
label: fabianmichael.meta.og_site_name.label
placeholder: "{{ site.title }}"
help: fabianmichael.meta.og_site_name.help
og_image:
extends: fields/meta/og-image
query: site.images.metaFilterOgImages
label: fabianmichael.meta.global_og_image.label
help: fabianmichael.meta.global_og_image.help

View file

@ -0,0 +1,88 @@
<?php
use FabianMichael\Meta\Helper;
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby): array {
$toggleType = Helper::toggleFieldType();
$getOptions = function (string $name) use ($kirby, $toggleType): array {
$optionValue = $kirby->option('fabianmichael.meta.' . str_replace('_', '.', $name));
$configDefaultLabel = tt('fabianmichael.meta.config_default_value.label', [
'state' => ($optionValue === true ? t('fabianmichael.meta.state.on') : t('fabianmichael.meta.state.off')),
]);
if (in_array($toggleType, ['multi-toggle', 'toggles'])) {
return [
'options' => [
[
'value' => '',
'text' => $configDefaultLabel,
],
[
'value' => '1',
'text' => t('fabianmichael.meta.state.on'),
],
[
'value' => '0',
'text' => t('fabianmichael.meta.state.off'),
],
],
'reset' => false,
'grow' => false,
'type' => $toggleType,
'translate' => false,
'width' => '1/2',
];
} else {
return [
'placeholder' => $configDefaultLabel,
'options' => [
[
'value' => '1',
'text' => t('fabianmichael.meta.state.on'),
],
[
'value' => '0',
'text' => t('fabianmichael.meta.state.off'),
],
],
'type' => $toggleType,
'translate' => false,
'width' => '1/2',
];
}
};
return [
'type' => 'group',
'fields' => [
'robots_headline' => [
'type' => 'headline',
'label' => t('fabianmichael.meta.global_robots.headline'),
'help' => t('fabianmichael.meta.global_robots.help'),
'numbered' => false,
],
'robots_index' => array_merge([
'label' => t('fabianmichael.meta.global_robots_index.label'),
'help' => t('fabianmichael.meta.global_robots_index.help'),
], $getOptions('robots_index')),
'robots_follow' => array_merge([
'label' => t('fabianmichael.meta.global_robots_follow.label'),
'help' => t('fabianmichael.meta.global_robots_follow.help'),
], $getOptions('robots_follow')),
'robots_archive' => array_merge([
'label' => t('fabianmichael.meta.global_robots_archive.label'),
'help' => t('fabianmichael.meta.global_robots_archive.help'),
], $getOptions('robots_archive')),
'robots_imageindex' => array_merge([
'label' => t('fabianmichael.meta.global_robots_imageindex.label'),
'help' => t('fabianmichael.meta.global_robots_imageindex.help'),
], $getOptions('robots_imageindex')),
'robots_snippet' => array_merge([
'label' => t('fabianmichael.meta.global_robots_snippet.label'),
'help' => t('fabianmichael.meta.global_robots_snippet.help'),
], $getOptions('robots_snippet')),
],
];
};

View file

@ -0,0 +1,72 @@
type: group
fields:
meta_schema_headline:
type: headline
label: fabianmichael.meta.schema.headline
numbered: false
help: fabianmichael.meta.schema.help
meta_website_owner:
type: select
label: fabianmichael.meta.schema.website_owner.label
options:
person: Person
org: Organization
translate: false
help: fabianmichael.meta.schema.website_owner.help
meta_org_name:
type: text
label: fabianmichael.meta.schema.org_name.label
required: true
translate: false
when:
meta_website_owner: org
meta_org_logo:
type: files
label: fabianmichael.meta.schema.org_logo.label
layout: cards
size: small
multiple: false
query: site.files.filterBy("mime", "in", ["image/jpeg", "image/png", "image/svg+xml"])
uploads: meta-logo
image:
back: white
when:
meta_website_owner: org
meta_person:
type: users
label: fabianmichael.meta.schema.meta_person.label
multiple: false
required: true
empty: fabianmichael.meta.schema.meta_person.empty
help: fabianmichael.meta.schema.meta_person.help
translate: false
when:
meta_website_owner: person
meta_privacy_notice:
type: info
theme: notice
label: fabianmichael.meta.schema.person_privacy_notice.label
text: fabianmichael.meta.schema.person_privacy_notice.text
when:
meta_website_owner: person
# meta_page_type:
# type: select
# label: Page type
# options:
# - WebPage
# - ItemPage
# - AboutPage
# - FAQPage
# - QAPage
# - ProfilePage
# - ContactPage
# - MedicalWebPage
# - CollectionPage
# - CheckoutPage
# - RealEstateListing
# - SearchResultsPage
# meta_article_type:
# type: select
# label: Article page
# options:
# -

View file

@ -0,0 +1,42 @@
<?php
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby) {
return [
'type' => 'select',
'label' => t('fabianmichael.meta.sitemap.changefreq.label'),
'translate' => false,
'options' => [
[
'value' => 'always',
'text' => t('fabianmichael.meta.sitemap.changefreq.always'),
],
[
'value' => 'hourly',
'text' => t('fabianmichael.meta.sitemap.changefreq.hourly'),
],
[
'value' => 'daily',
'text' => t('fabianmichael.meta.sitemap.changefreq.daily'),
],
[
'value' => 'weekly',
'text' => t('fabianmichael.meta.sitemap.changefreq.weekly'),
],
[
'value' => 'monthly',
'text' => t('fabianmichael.meta.sitemap.changefreq.monthly'),
],
[
'value' => 'yearly',
'text' => t('fabianmichael.meta.sitemap.changefreq.yearly'),
],
[
'value' => 'never',
'text' => t('fabianmichael.meta.sitemap.changefreq.never'),
],
],
'help' => t('fabianmichael.meta.sitemap.changefreq.help'),
];
};

View file

@ -0,0 +1,20 @@
type: group
fields:
twitter_headline:
type: headline
label: Twitter
numbered: false
twitter_site:
type: text
label: fabianmichael.meta.twitter.site.label
counter: false
before: "@"
icon: twitter
width: 1/2
twitter_creator:
type: text
label: fabianmichael.meta.twitter.creator.label
counter: false
before: "@"
icon: twitter
width: 1/2

View file

@ -0,0 +1,12 @@
type: files
label: fabianmichael.meta.og_image.label
multiple: false
empty: fabianmichael.meta.image.empty
layout: cards
size: small
image:
back: white
ratio: 1200/630
cover: true
uploads: meta-og-image
help: fabianmichael.meta.og_image.help

View file

@ -0,0 +1,20 @@
type: group
fields:
og_headline:
type: headline
label: fabianmichael.meta.og.headline
numbered: false
help: fabianmichael.meta.og.help
og_title:
type: text
label: fabianmichael.meta.og_title.label
placeholder: "{{ page.meta_title.or(page.title) }}"
help: fabianmichael.meta.og_title.help
og_description:
type: text
label: fabianmichael.meta.og_description.label
placeholder: "{{ page.meta_description.or(site.meta_description) }}"
help: fabianmichael.meta.og_description.help
og_image:
extends: fields/meta/og-image
query: page.images.metaFilterOgImages

View file

@ -0,0 +1,94 @@
<?php
use FabianMichael\Meta\Helper;
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby): array {
$toggleType = Helper::toggleFieldType();
$getOptions = function (string $name) use ($kirby, $toggleType): array {
$globalValue = $kirby
->site()
->content()
->get($name)
->or($kirby->option('fabianmichael.meta.' . str_replace('_', '.', $name)))
->toBool();
$configDefaultLabel = tt('fabianmichael.meta.global_default_value.label', [
'state' => ($globalValue === true ? t('fabianmichael.meta.state.on') : t('fabianmichael.meta.state.off')),
]);
if (in_array($toggleType, ['multi-toggle', 'toggles'])) {
return [
'options' => [
[
'value' => '',
'text' => $configDefaultLabel,
],
[
'value' => '1',
'text' => t('fabianmichael.meta.state.on'),
],
[
'value' => '0',
'text' => t('fabianmichael.meta.state.off'),
],
],
'reset' => false,
'grow' => false,
'type' => $toggleType,
'translate' => false,
'width' => '1/2',
];
} else {
return [
'placeholder' => $configDefaultLabel,
'options' => [
[
'value' => '1',
'text' => t('fabianmichael.meta.state.on'),
],
[
'value' => '0',
'text' => t('fabianmichael.meta.state.off'),
],
],
'type' => $toggleType,
'translate' => false,
'width' => '1/2',
];
}
};
return [
'type' => 'group',
'fields' => [
'robots_headline' => [
'type' => 'headline',
'label' => t('fabianmichael.meta.robots.headline'),
'help' => t('fabianmichael.meta.robots.help'),
'numbered' => false,
],
'robots_index' => array_merge([
'label' => t('fabianmichael.meta.robots_index.label'),
'help' => t('fabianmichael.meta.robots_index.help'),
], $getOptions('robots_index')),
'robots_follow' => array_merge([
'label' => t('fabianmichael.meta.robots_follow.label'),
'help' => t('fabianmichael.meta.robots_follow.help'),
], $getOptions('robots_follow')),
'robots_archive' => array_merge([
'label' => t('fabianmichael.meta.robots_archive.label'),
'help' => t('fabianmichael.meta.robots_archive.help'),
], $getOptions('robots_archive')),
'robots_imageindex' => array_merge([
'label' => t('fabianmichael.meta.robots_imageindex.label'),
'help' => t('fabianmichael.meta.robots_imageindex.help'),
], $getOptions('robots_imageindex')),
'robots_snippet' => array_merge([
'label' => t('fabianmichael.meta.robots_snippet.label'),
'help' => t('fabianmichael.meta.robots_snippet.help'),
], $getOptions('robots_snippet')),
],
];
};

View file

@ -0,0 +1,53 @@
<?php
use FabianMichael\Meta\SiteMeta;
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby) {
$defaultState = SiteMeta::changefreq();
$defaultState = $defaultState !== null
? t("fabianmichael.meta.sitemap.changefreq.{$defaultState}")
: t('fabianmichael.meta.state.unset');
$placeholder = tt('fabianmichael.meta.global_default_value.label', [
'state' => $defaultState,
]);
return [
'type' => 'select',
'label' => t('fabianmichael.meta.sitemap.changefreq.label'),
'placeholder' => $placeholder,
'translate' => false,
'options' => [
[
'value' => 'always',
'text' => t('fabianmichael.meta.sitemap.changefreq.always'),
],
[
'value' => 'hourly',
'text' => t('fabianmichael.meta.sitemap.changefreq.hourly'),
],
[
'value' => 'daily',
'text' => t('fabianmichael.meta.sitemap.changefreq.daily'),
],
[
'value' => 'weekly',
'text' => t('fabianmichael.meta.sitemap.changefreq.weekly'),
],
[
'value' => 'monthly',
'text' => t('fabianmichael.meta.sitemap.changefreq.monthly'),
],
[
'value' => 'yearly',
'text' => t('fabianmichael.meta.sitemap.changefreq.yearly'),
],
[
'value' => 'never',
'text' => t('fabianmichael.meta.sitemap.changefreq.never'),
],
],
'help' => t('fabianmichael.meta.sitemap.changefreq.help'),
];
};

View file

@ -0,0 +1,9 @@
type: range
label: fabianmichael.meta.sitemap.priority.label
min: 0
max: 1
step: 0.1
default: 0.5
help: fabianmichael.meta.sitemap.priority.help
translate: false
width: 1/2

View file

@ -0,0 +1,14 @@
type: group
fields:
twitter_headline:
type: headline
label: fabianmichael.meta.twitter.headline
numbered: false
twitter_creator:
type: text
label: Twitter username of content creator
placeholder: "{{ site.twitter_creator }}"
counter: false
before: "@"
icon: twitter
width: 1/2

View file

@ -0,0 +1,4 @@
title: Logo
accept:
mime: image/jpeg, image/png, image/svg+xml

View file

@ -0,0 +1,15 @@
title: Social media share image
accept:
mime: image/jpeg, image/png, image/webp, image/avif, image/gif
# maxwidth: 4096 # Twitter
# maxheight: 4096 # Twitter
minwidth: 300 # Twitter
minheight: 157 # Twitter
# maxsize: 5000000 # 5 MB Twitter, 8 MB Facebook
fields:
alt:
type: text
label: Alternative text
help: Used by assistive technology and automated system for describing image contents.

View file

@ -0,0 +1,2 @@
type: files
headline: fabianmichael.meta.files.headline

View file

@ -0,0 +1,2 @@
type: meta-share-preview
label: fabianmichael.meta.sharing_preview.headline

View file

@ -0,0 +1,3 @@
label: fabianmichael.meta.status.label
type: stats
reports: page.meta.reports

View file

@ -0,0 +1,57 @@
<?php
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby) {
$columns = [];
$fields = [];
$sections = [];
// main column
$fields['meta_general'] = 'fields/meta/general-group';
if ($kirby->option('fabianmichael.meta.social') !== false) {
$fields ['meta_opengraph'] = 'fields/meta/opengraph-group';
if ($kirby->option('fabianmichael.meta.twitter')) {
$fields['meta_twitter'] = 'fields/meta/twitter-group';
}
$sections['meta_sharing_preview'] = 'sections/meta/share-preview';
$sections['meta_files'] = 'sections/meta/files';
}
// robots
if ($kirby->option('fabianmichael.meta.robots') !== false) {
$fields['meta_robots'] = 'fields/meta/robots-group';
}
// stats (only Kirby 3.7+)
if ($kirby->extension('sections', 'stats')) {
$sections['meta_status'] = 'sections/meta/status';
}
// compose columns
$columns['meta_main'] = [
'width' => '2/3',
'fields' => $fields,
];
if (sizeof($sections) > 0) {
$columns['meta_sidebar'] = [
'sticky' => true,
'width' => '1/3',
'sections' => $sections,
];
}
return [
'icon' => 'search',
'label' => t('fabianmichael.meta.tab.label'),
'columns' => $columns,
];
};

View file

@ -0,0 +1,43 @@
<?php
use Kirby\Cms\App as Kirby;
return function (Kirby $kirby) {
$fields = [
'meta_global_general' => 'fields/meta/global-general-group',
];
if ($kirby->option('fabianmichael.meta.schema') !== false) {
$fields['meta_global_schema'] = 'fields/meta/global-schema-group';
}
if ($kirby->option('fabianmichael.meta.social') !== false) {
$fields['meta_global_ogengraph'] = 'fields/meta/global-opengraph-group';
if ($kirby->option('fabianmichael.meta.twitter')) {
$fields['meta_global_twitter'] = 'fields/meta/global-twitter-group';
}
}
if ($kirby->option('fabianmichael.meta.robots') !== false) {
$fields['meta_global_robots'] = 'fields/meta/global-robots-group';
}
return [
'icon' => 'search',
'label' => t('fabianmichael.meta.tab.label'),
'columns' => [
'meta_main' => [
'width' => '2/3',
'fields' => $fields,
],
'meta_sidebar' => [
'sticky' => true,
'width' => '1/3',
'sections' => [
'meta_files' => 'sections/meta/files',
],
],
],
];
};

View file

@ -0,0 +1,48 @@
{
"name": "fabianmichael/kirby-meta",
"type": "kirby-plugin",
"version": "2.0.0",
"license": "MIT",
"description": "Your all-in-one powerhouse for any SEO and metadata needs imaginable.",
"homepage": "https://github.com/fabianmichael/kirby-meta",
"authors": [
{
"name": "Fabian Michael",
"email": "hallo@fabianmichael.de"
}
],
"keywords": [
"kirby3",
"kirby3-cms",
"kirby3-plugin",
"meta",
"metadata",
"seo",
"panel"
],
"autoload": {
"psr-4": {
"FabianMichael\\Meta\\": "src/"
}
},
"config": {
"optimize-autoloader": true,
"allow-plugins": {
"getkirby/composer-installer": true
}
},
"require": {
"php": ">=8.0.0",
"getkirby/composer-installer": "^1.2"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.8"
},
"extra": {
"installer-name": "meta"
},
"scripts": {
"cs-fixer": "vendor/bin/php-cs-fixer fix --dry-run --diff",
"cs-fixer-fix": "vendor/bin/php-cs-fixer fix --diff"
}
}

2145
site/plugins/meta/composer.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,146 @@
<?php
use Kirby\Cms\Response;
use Kirby\Cms\Url;
use Kirby\Http\Header;
use Kirby\Toolkit\Str;
return [
'routes' => [
[
'pattern' => 'meta/check-internal-links',
'action' => function () {
$id = get('id');
$language = get('language');
$baseUrl = url();
if (empty($id) === true) {
return Response::json("Empty ID parameter.", 500);
}
if (kirby()->multilang() && empty($language) === true) {
return Response::json("Empty language parameter.", 500);
}
$page = kirby()->page($id);
if ($page === null) {
return Response::json("The page with $id could not be found.", 500);
}
site()->visit($page, $language);
// intercept redirects, so the link checker always returns
// a 200 status code.
$handleRedirect = function () use ($baseUrl) {
if (in_array(http_response_code(), [301, 302, 303, 304, 307])) {
$target = '';
foreach (headers_list() as $header) {
if (Str::contains($header, ':') === false) {
continue;
}
list($key, $value) = explode(':', $header, 2);
if (strtolower($key) === 'location') {
$target = str_replace($baseUrl, '', trim($value));
break;
}
}
header_remove('location');
Header::success();
echo Response::json([
'type' => 'redirect',
'message' => "Links where not checked, because page is a redirect to:\n{$target}",
], 200);
}
};
header_register_callback($handleRedirect);
register_shutdown_function($handleRedirect);
$html = kirby()->impersonate('nobody', fn () => $page->render());
$brokenLinks = [];
try {
$doc = new DOMDocument();
$doc->validateOnParse = true;
libxml_use_internal_errors(true);
$doc->loadHTML($html);
libxml_clear_errors();
$elements = array_merge(
iterator_to_array($doc->getElementsByTagName('a')),
);
foreach ($elements as $item) {
$href = $item->getAttribute('href');
if (empty($href) === true || $href === '#') {
continue;
}
if (Str::contains($href, '#') === true) {
// anchor link
list($targetUrl, $targetId) = explode('#', $href);
if (empty($targetUrl) === true || $targetUrl === $page->url()) {
$targetEl = $doc->getElementById($targetId);
} else {
// only evaluate same-page anchor links for now.
continue;
}
if ($targetEl === null) {
// broken anchor link
$brokenLinks[] = "Broken anchor link: <code>{$href}</code>";
}
continue;
} else {
if (Str::startsWith($href, '/')) {
$href = $baseUrl . $href;
}
if (Str::startsWith($href, $baseUrl) === false) {
// skip external links
continue;
}
if (Str::contains(pathinfo($href, PATHINFO_BASENAME), '.')) {
// skip links to files
continue;
}
$path = trim(parse_url($href, PHP_URL_PATH), '/');
if (empty($path) === true) {
// skip links to homepage
continue;
}
if (kirby()->router()->call($path) === null) {
// target page does not exist
$brokenLinks[] = "Link to non-existant page: <code>" . Url::short($href) . "</code>";
}
}
}
} catch (Exception $e) {
return Response::json([
'type' => 'page',
'message' => $e->getMessage(),
], 500);
}
return Response::json([
'type' => 'page',
'message' => sizeof($brokenLinks) > 0 ? "This page contains broken links:" : null,
'brokenLinks' => $brokenLinks,
], 200);
},
],
],
];

View file

@ -0,0 +1,28 @@
<?php
use FabianMichael\Meta\SiteMeta;
use Kirby\Cms\Site;
return [
'meta-title-preview' => [
'computed' => [
'siteTitle' => function () {
return $this->model->site()->title()->toString();
},
'separator' => function () {
return SiteMeta::titleSeparator();
},
'modelTitle' => function () {
if ($this->model instanceof Site) {
return null;
}
return $this->model->title()->toString();
},
'isHomePage' => function () {
return $this->model->isHomePage();
},
],
'save' => false,
],
];

View file

@ -0,0 +1,18 @@
<?php
use Kirby\Cms\Files;
return [
'metaFilterOgImages' => function (): Files {
return $this
->filterBy('mime', 'in', [
'image/jpeg',
'image/png',
'image/webp',
'image/avif',
'image/gif',
])
->filterBy('width', '>=', 300)
->filterBy('height', '>=', 157);
},
];

View file

@ -0,0 +1,14 @@
<?php
use FabianMichael\Meta\PageMeta;
use FabianMichael\Meta\SiteMap;
return [
'meta' => function (?string $languageCode = null) {
return PageMeta::of($this, $languageCode);
},
'isIndexible' => function(){
return Sitemap::isPageIndexible( $this );
},
];

View file

@ -0,0 +1,51 @@
<?php
use FabianMichael\Meta\SiteMeta;
use Kirby\Cms\App;
use Kirby\Cms\Page;
return function (App $kirby) {
$routes = [];
if ($kirby->option('fabianmichael.meta.robots') !== false) {
$routes[] = [
'pattern' => 'robots.txt',
'method' => 'ALL',
'action' => function () use ($kirby) {
$robots = [
'User-agent: *',
'Allow: /',
];
if ($kirby->option('fabianmichael.meta.sitemap') === true && SiteMeta::robots('index') === true) {
$robots[] = 'Sitemap: ' . url('sitemap.xml');
}
return $kirby
->response()
->type('text')
->body(implode(PHP_EOL, $robots));
},
];
}
$routes[] = [
'pattern' => 'sitemap.xml',
'action' => function () use ($kirby) {
if ($kirby->option('fabianmichael.meta.sitemap') === false || SiteMeta::robots('index') === false) {
$this->next();
}
return Page::factory([
'slug' => 'sitemap',
'template' => 'sitemap',
'model' => 'sitemap',
'content' => [
'title' => 'XML Sitemap',
],
])->render(contentType: 'xml');
},
];
return $routes;
};

View file

@ -0,0 +1,52 @@
<?php
use FabianMichael\Meta\SiteMeta;
return [
'meta-share-preview' => [
'mixins' => [
'headline',
],
'computed' => [
'metadata_og_image' => function (): ?array {
$image = $this->model()->meta()->metadata('og_image');
return $image ? $image->crop(1200, 630)->toArray() : null;
},
'page_is_homepage' => function (): bool {
return $this->model()->isHomePage();
},
'page_title' => function (): ?string {
return $this->model()->title()->value();
},
'page_metadata_description' => function (): ?string {
return $this->model()->meta()->metadata('meta_description');
},
'site_meta_description' => function (): ?string {
return $this->model()->site()->content()->get('meta_description')->value();
},
'site_name' => function (): ?string {
$site = $this->model()->site();
return $site->og_site_name()->or($site->title())->value();
},
'site_og_image' => function (): ?array {
$image = $this->model()->site()->content()->get('og_image')->toFile();
return $image ? $image->crop(1200, 630)->toArray() : null;
},
'site_title' => function (): ?string {
return $this->model()->site()->title()->value();
},
'title_separator' => function (): string {
return SiteMeta::titleSeparator();
},
'og_title_prefix' => function (): ?string {
return $this->model()->meta()->get('og_title_prefix')->value();
},
'url' => function (): string {
return $this->model()->url();
},
],
],
];

View file

@ -0,0 +1,23 @@
<?php
return [
'metaPanelWarning' => function (string $type) {
$text = '';
if ($type === 'no_og_image_fallback') {
if (site()->og_image()->toFile() === null) {
$text = tt('fabianmichael.meta.no_og_image_fallback', [
'link' => $this->panel()->url() . '?tab=meta',
]);
}
}
if (empty($text) === false) {
return '<span data-theme="notice" class="k-meta-warning-box">' . $text . '</span>';
}
},
'indexedPages' => function () {
return $this->index()->filterBy('isIndexible', '==', true);
},
];

View file

@ -0,0 +1,62 @@
<?php
use FabianMichael\Meta\Sitemap;
use Kirby\Cms\Url;
return [
[
'pattern' => 'meta',
'action' => function () {
$pages = [];
$index = site()->index();
if (is_callable($filter = option('fabianmichael.meta.panel.view.filter', null))) {
$index = $index->filter($filter);
}
foreach ($index as $page) {
$meta = $page->meta();
if ($og_image = $meta->og_image()) {
if ($og_image->exists() === true) {
// Only resize, if given image does actually exists
// and is accessible
$og_image_url = $og_image->crop(192, 101)->url();
} else {
// Probably a virtual file
$og_image_url = $og_image->url();
}
} else {
$og_image_url = null;
}
$pages[] = [
'title' => $page->title()->value(),
'meta_title' => $meta->get('meta_title')->value(),
'icon' => $page->blueprint()->icon(),
'is_indexible' => Sitemap::isPageIndexible($page),
'status' => $page->status(),
'id' => $page->id(),
'url' => $page->url(),
'shortUrl' => Url::short($page->url()),
'template' => $page->template()->name(),
'panelUrl' => $page->panel()->url(),
'meta_description' => $meta->meta_description()->value(),
'robots' => $meta->robots(),
'og_title' => $meta->og_title()->value(),
'og_description' => $meta->get('og_description', true, false)->value(),
'og_image_url' => $og_image_url,
'og_image_alt' => $og_image?->alt()->value(),
];
}
return [
'component' => 'k-meta-view',
'props' => [
'pages' => $pages,
],
];
},
],
];

View file

@ -0,0 +1 @@
[dir=ltr] .k-meta-warning-box{border-left:2px solid var(--theme-light)}[dir=rtl] .k-meta-warning-box{border-right:2px solid var(--theme-light)}.k-meta-warning-box{display:block;background:var(--theme-bg);color:var(--color-dark);border-radius:var(--rounded-xs);line-height:1.25rem;margin-top:var(--spacing-4);padding:.5rem 1.5rem}.k-meta-sharing-preview__label{display:flex}.k-meta-sharing-preview__label>*+*{margin-left:var(--spacing-2);padding-top:var(--spacing-px)}.k-meta-sharing-preview__source-badge{background:var(--color-gray-900);color:var(--color-white);border-radius:var(--rounded-sm);bottom:var(--spacing-2);position:absolute;right:var(--spacing-2);font-size:.625rem;line-height:var(--leading-none);padding:var(--spacing-1) var(--spacing-2)}.k-meta-sharing-preview__box{background:var(--color-white);border-radius:var(--rounded);box-shadow:var(--shadow);display:flex;flex-direction:column;max-width:438px;overflow:hidden;position:relative;width:100%}.k-meta-sharing-preview__image-container{background:var(--bg-pattern) var(--color-gray-800);padding-bottom:52.25%;position:relative;width:100%}.k-meta-sharing-preview__image-container[data-image-missing]:before{content:attr(data-image-missing-text);color:var(--color-white);position:absolute;font-size:1.5em;top:50%;left:50%;width:100%;text-align:center;transform:translate(-50%,-50%) rotate(-20deg)}.k-meta-sharing-preview__preview-image{position:absolute;width:100%;height:100%;object-fit:cover}.k-meta-sharing-preview__content-container{padding:var(--spacing-2) var(--spacing-3) var(--spacing-3)}.k-meta-sharing-preview__site-name{color:var(--color-gray-600);font-size:var(--text-xs)}.k-meta-sharing-preview__url{color:var(--color-gray-500);font-size:var(--text-xs);margin-top:var(--spacing-3)}.k-meta-sharing-preview__preview-headline{color:var(--color-dark);font-size:var(--text-base);line-height:var(--leading-tight);margin:var(--spacing-1) 0;padding:0}.k-meta-sharing-preview__preview-paragraph{color:var(--color-gray-600);font-size:var(--text-sm);line-height:var(--leading-normal);margin:0;padding:0}.k-meta-title-preview__content{border:var(--field-input-border);background:var(--color-gray-300);border-radius:var(--rounded);padding:var(--field-input-padding);min-height:var(--input-height);display:grid;align-items:center;gap:.75ch;grid-template-columns:min-content 1fr}.k-k-meta-title-separator-preview__favicon{border-radius:2px;height:1rem;width:1rem;max-width:none}.k-meta-title-preview__title{overflow:hidden;text-overflow:ellipsis;font-size:var(--text-sm);height:var(--field-input-line-height);position:relative;top:.07em;white-space:nowrap;padding-top:.1em;padding-bottom:.1em}.k-meta{width:calc(100% - var(--spacing-4));margin:0 var(--spacing-2);table-layout:fixed;border-spacing:0}.k-meta td,.k-meta th{text-align:left;font-size:var(--text-sm);padding:var(--spacing-2);vertical-align:top}.k-meta th{font-weight:500}.k-meta thead th{border-top-left-radius:var(--rounded);border-top-right-radius:var(--rounded);position:sticky;top:0;z-index:10}.k-meta tbody tr:last-child td{border-bottom-left-radius:var(--rounded);border-bottom-right-radius:var(--rounded)}.k-meta td:first-child,.k-meta th:first-child{padding-left:calc(var(--spacing-2) + 1rem)}.k-meta td:nth-child(even),.k-meta th:nth-child(even){background:var(--color-gray-100)}.k-meta td:nth-child(odd),.k-meta th:nth-child(odd){background:var(--color-background)}.k-meta tbody tr:not([data-is-indexible="true"]){color:var(--color-gray-600)}.k-meta tbody tr:not([data-is-indexible="true"]) .k-image{opacity:.8}.k-meta .k-meta-result{color:var(--color-gray-900);padding-right:0}.k-meta .k-meta-result-content{padding:var(--spoacing-3);background:var(--color-white)}.k-meta-title{display:flex}.k-meta-title>*+*{margin-left:var(--spacing-2)}.k-meta-caps{text-transform:uppercase;font-size:var(--text-xs);font-weight:600;line-height:1rem;letter-spacing:.02em;width:100%;overflow:hidden;text-overflow:ellipsis}.k-meta-thumbnail-col{box-sizing:content-box;width:6rem}.k-meta-thumbnail-col .k-image{display:block;margin:0 auto;width:6rem}.k-meta-center{text-align:center}.k-meta .k-meta-page-header-col{padding:0!important}.k-meta-page-header{position:relative;align-items:center;display:grid;gap:var(--spacing-2);grid-template-columns:min-content 1fr 3fr auto;background:var(--color-white);border-radius:var(--rounded);box-shadow:var(--shadow);padding:var(--spacing-2);margin:0 calc(-1 * var(--spacing-2))}.k-meta-infozone{font-weight:var(--font-normal);color:var(--color-gray-500);font-size:var(--text-xs);font-family:var(--font-mono);display:flex}.k-meta-infozone>*+*{margin-left:var(--spacing-2)}.k-meta-infozone .k-icon{--size: .75rem}.k-meta-status-wrap{height:1rem;width:1rem;line-height:1;pointer-events:none}.k-meta-text-xs{font-size:var(--text-xs);line-height:var(--leading-snug)}.k-meta-max-3-lines{width:100%;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,99 @@
<?php
use FabianMichael\Meta\SitemapPage;
use Kirby\Cms\App;
@include_once __DIR__ . '/vendor/autoload.php';
App::plugin('fabianmichael/meta', [
'options' => [
'cache' => true,
'sitemap' => true,
'sitemap.detailSettings' => false,
'sitemap.pages.exclude' => [],
'sitemap.pages.includeUnlisted' => [],
'sitemap.templates.exclude' => [],
'sitemap.templates.includeUnlisted' => [],
'schema' => true,
'social' => true,
'twitter' => false,
'robots' => true,
'robots.canonical' => true,
'robots.index' => true,
'robots.follow' => true,
'robots.archive' => true,
'robots.imageindex' => true,
'robots.snippet' => true,
'robots.translate' => true,
'robots.forceNoIndex' => false,
'title.separators' => ['~' , '-' , '' , '—' , ':' , '/' , '⋆' , '·' , '•' , '~' , '×' , '*' , '‣', '→', '←', '<' , '>' , '«' , '»' , '' , '', '♠︎', '♣︎', '♥︎', '♦︎', '☙', '❦', '❧', '☭'],
'theme.color' => null,
'panel.view.filter' => null,
],
'api' => require __DIR__ . '/config/api.php',
'areas' => [
'meta' => [
'label' => 'Metadata',
'icon' => 'search',
'menu' => true,
'views' => require __DIR__ . '/config/views.php',
],
],
'blueprints' => [
'fields/meta/general-group' => require __DIR__ . '/blueprints/fields/meta/general-group.php',
'fields/meta/global-general-group' => require __DIR__ . '/blueprints/fields/meta/global-general-group.php',
'fields/meta/global-opengraph-group' => __DIR__ . '/blueprints/fields/meta/global-opengraph-group.yml',
'fields/meta/global-robots-group' => require __DIR__ . '/blueprints/fields/meta/global-robots-group.php',
'fields/meta/global-schema-group' => __DIR__ . '/blueprints/fields/meta/global-schema-group.yml',
'fields/meta/global-sitemap-changefreq' => require __DIR__ . '/blueprints/fields/meta/global-sitemap-changefreq.php',
'fields/meta/global-twitter-group' => __DIR__ . '/blueprints/fields/meta/global-twitter-group.yml', // deprecated
'fields/meta/og-image' => __DIR__ . '/blueprints/fields/meta/og-image.yml',
'fields/meta/opengraph-group' => __DIR__ . '/blueprints/fields/meta/opengraph-group.yml',
'fields/meta/robots-group' => require __DIR__ . '/blueprints/fields/meta/robots-group.php',
'fields/meta/sitemap-changefreq' => require __DIR__ . '/blueprints/fields/meta/sitemap-changefreq.php',
'fields/meta/sitemap-priority' => __DIR__ . '/blueprints/fields/meta/sitemap-priority.yml',
'fields/meta/twitter-group' => __DIR__ . '/blueprints/fields/meta/twitter-group.yml', // deprecated
'files/meta-logo' => __DIR__ . '/blueprints/files/meta-logo.yml',
'files/meta-og-image' => __DIR__ . '/blueprints/files/meta-og-image.yml',
'sections/meta/files' => __DIR__ . '/blueprints/sections/files.yml',
'sections/meta/share-preview' => __DIR__ . '/blueprints/sections/share-preview.yml',
'sections/meta/status' => __DIR__ . '/blueprints/sections/status.yml',
'tabs/meta/page' => require __DIR__ . '/blueprints/tabs/page.php',
'tabs/meta/site' => require __DIR__ . '/blueprints/tabs/site.php',
],
'fields' => require __DIR__ . '/config/fields.php',
'filesMethods' => require __DIR__ . '/config/files-methods.php',
'routes' => require __DIR__ . '/config/routes.php',
'pageMethods' => require __DIR__ . '/config/page-methods.php',
'pageModels' => [
'sitemap' => SitemapPage::class,
],
'sections' => require __DIR__ . '/config/sections.php',
'siteMethods' => require __DIR__ . '/config/site-methods.php',
'snippets' => [
'meta' => __DIR__ . '/snippets/meta.php',
'meta/general' => __DIR__ . '/snippets/general.php',
'meta/robots' => __DIR__ . '/snippets/robots.php',
'meta/social' => __DIR__ . '/snippets/social.php',
'meta/schema' => __DIR__ . '/snippets/schema.php',
],
'templates' => [
'sitemap' => __DIR__ . '/templates/sitemap.php',
'sitemap.xml' => __DIR__ . '/templates/sitemap.xml.php',
],
'translations' => [
'da' => require __DIR__ . '/translations/da.php',
'de' => require __DIR__ . '/translations/de.php',
'en' => require __DIR__ . '/translations/en.php',
'fr' => require __DIR__ . '/translations/fr.php',
'sv_SE' => require __DIR__ . '/translations/sv_SE.php',
],
]);

5035
site/plugins/meta/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
{
"scripts": {
"dev": "npx -y kirbyup panel/index.js --watch",
"build": "npx -y kirbyup panel/index.js"
},
"devDependencies": {
"kirbyup": "^0.22.2"
}
}

View file

@ -0,0 +1,342 @@
<template>
<k-inside>
<k-view>
<k-header>
Metadata
<k-button-group slot="left">
<k-button
text="Validate internal links"
icon="wand"
:disabled="isBusy"
@click="checkInternalLinks"
/>
<k-languages-dropdown />
</k-button-group>
</k-header>
<table class="k-meta">
<thead>
<tr>
<th>
<span class="k-meta-title">
<span class="k-meta-caps">Title Override</span>
</span>
</th>
<th>
<span class="k-meta-title">
<span class="k-meta-caps">Meta Description</span>
</span>
</th>
<th>
<span class="k-meta-title">
<span class="k-meta-caps">Share Title</span>
</span>
</th>
<th style="width: 14rem">
<span class="k-meta-title">
<span class="k-meta-caps">Share Description</span>
</span>
</th>
<th class="k-meta-thumbnail-col">
<k-icon type="image" />
</th>
<th style="width: 14rem">
<span class="k-meta-title">
<k-icon type="image" />
<span class="k-meta-caps">Alt</span>
</span>
</th>
<th style="width: 3rem">
<span class="sr-only">Robots</span>
<k-icon type="meta-robot" />
</th>
<th style="width: 3rem">
<span class="sr-only">Link validation</span>
<k-icon type="url" />
</th>
</tr>
</thead>
<tbody>
<template v-for="(page, id) in pages" >
<tr
:key="id + '_head'"
:data-is-indexible="page.is_indexible"
>
<th colspan="8" class="k-meta-page-header-col">
<div class="k-meta-page-header">
<div class="k-meta-status-wrap">
<k-status-icon :status="page.status" />
</div>
<k-link :to="page.panelUrl">{{ page.title }}</k-link>
<a :href="page.url" target="_blank" rel="noopener" class="k-meta-infozone">
<k-icon type="url"/>
<span>{{ page.shortUrl }}</span>
</a>
<span class="k-meta-infozone">
<k-icon :type="page.icon || 'page'"/>
<span>{{ page.template }}</span>
</span>
</div>
</th>
</tr>
<tr
:key="id + '_content'"
:data-is-indexible="page.is_indexible"
>
<td>
<div v-if="page.meta_title" class="k-meta-text-xs k-meta-max-3-lines">{{ page.meta_title }}</div>
<template v-else></template>
</td>
<td>
<div v-if="page.meta_description" class="k-meta-text-xs k-meta-max-3-lines">{{ page.meta_description }}</div>
<template v-else></template>
</td>
<td>
<div v-if="page.og_title" class="k-meta-text-xs k-meta-max-3-lines">{{ page.og_title }}</div>
<template v-else></template>
</td>
<td>
<div v-if="page.og_description" class="k-meta-text-xs k-meta-max-3-lines">{{ page.og_description }}</div>
<div v-else-if="page.meta_description" class="k-meta-text-xs k-meta-max-3-lines" style="opacity: 0.5;">[Meta description]</div>
<template v-else></template>
</td>
<td class="k-meta-thumbnail-col">
<k-image
v-if="page.og_image_url"
:src="page.og_image_url"
:cover="true"
ratio="1200/630"
back="pattern"
/>
<div v-else class="k-meta-center"></div>
</td>
<td>
<div v-if="page.og_image_alt" class="k-meta-text-xs k-meta-max-3-lines">{{ page.og_image_alt}}</div>
<template v-else></template>
</td>
<td><div class="k-meta-center"><k-icon :type="page.is_indexible ? 'meta-true' : 'meta-false'"/></div></td>
<td>
<div class="k-meta-center">
<k-icon
:type="(page.internalLinksResult && page.internalLinksResult.message) ? 'meta-false' : 'meta-true'"
v-if="page.internalLinksResult"
/>
<template v-else></template>
</div>
</td>
</tr>
<tr
:key="id + '_internal_links_result'"
v-if="page.internalLinksResult && page.internalLinksResult.message"
>
<td colspan="8" class="k-meta-result">
<k-box theme="negative">
<k-text size="tiny">
<p>{{ page.internalLinksResult.message }}</p>
<ul v-if="page.internalLinksResult.brokenLinks">
<li v-for="(value, index) in page.internalLinksResult.brokenLinks" :key="index" v-html="value"/>
</ul>
</k-text>
</k-box>
</td>
</tr>
</template>
</tbody>
</table>
</k-view>
</k-inside>
</template>
<script>
export default {
props: {
dir: String,
sort: String,
pages: Object,
},
data() {
return {
isBusy: false,
}
},
methods: {
async checkInternalLinks() {
this.isBusy = true;
// Reset
for (let i = 0, l = this.pages.length; i < l; i++) {
const page = this.pages[i];
page.internalLinksResult = null;
this.$set(this.pages, i, page);
}
// Get new results
for (let i = 0, l = this.pages.length; i < l; i++) {
const page = this.pages[i];
const id = page.id;
const result = await this.$api.get(`meta/check-internal-links`, {
id,
language: (this.$multilang ? this.$language.code : null),
});
page.internalLinksResult = result;
this.$set(this.pages, i, page);
}
this.isBusy = false;
},
},
};
</script>
<style>
.k-meta {
width: calc(100% - var(--spacing-4));
margin: 0 var(--spacing-2);
table-layout: fixed;
border-spacing: 0;
}
.k-meta td,
.k-meta th {
text-align: left;
font-size: var(--text-sm);
padding: var(--spacing-2);
vertical-align: top;
}
.k-meta th {
font-weight: 500;
}
.k-meta thead th {
border-top-left-radius: var(--rounded);
border-top-right-radius: var(--rounded);
position: sticky;
top: 0; /* Don't forget this, required for the stickiness */
z-index: 10;
}
.k-meta tbody tr:last-child td {
border-bottom-left-radius: var(--rounded);
border-bottom-right-radius: var(--rounded);
}
.k-meta td:first-child,
.k-meta th:first-child {
padding-left: calc(var(--spacing-2) + 1rem);
}
.k-meta td:nth-child(even),
.k-meta th:nth-child(even) {
background: var(--color-gray-100);
}
.k-meta td:nth-child(odd),
.k-meta th:nth-child(odd) {
background: var(--color-background);
}
.k-meta tbody tr:not([data-is-indexible="true"]) {
color: var(--color-gray-600);
}
.k-meta tbody tr:not([data-is-indexible="true"]) .k-image {
opacity: .8;
}
.k-meta .k-meta-result {
color: var(--color-gray-900);
padding-right: 0;
}
.k-meta .k-meta-result-content {
padding: var(--spoacing-3);
background: var(--color-white);
}
.k-meta-title {
display: flex;
}
.k-meta-title > * + * {
margin-left: var(--spacing-2);
}
.k-meta-caps {
text-transform: uppercase;
font-size: var(--text-xs);
font-weight: 600;
line-height: 1rem;
letter-spacing: .02em;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.k-meta-thumbnail-col {
box-sizing: content-box;
width: 6rem;
}
.k-meta-thumbnail-col .k-image {
display: block;
margin: 0 auto;
width: 6rem;
}
.k-meta-center {
text-align: center;
}
.k-meta .k-meta-page-header-col {
padding: 0 !important;
}
.k-meta-page-header {
position: relative;
align-items: center;
display: grid;
gap: var(--spacing-2);
grid-template-columns: min-content 1fr 3fr auto;
background: var(--color-white);
border-radius: var(--rounded);
box-shadow: var(--shadow);
padding: var(--spacing-2);
margin: 0 calc(-1 * var(--spacing-2));
}
.k-meta-infozone {
font-weight: var(--font-normal);
color: var(--color-gray-500);
font-size: var(--text-xs);
font-family: var(--font-mono);
display: flex;
}
.k-meta-infozone > * + * {
margin-left: var(--spacing-2);
}
.k-meta-infozone .k-icon {
--size: .75rem;
}
.k-meta-status-wrap {
height: 1rem;
width: 1rem;
line-height: 1;
pointer-events: none;
}
.k-meta-text-xs {
font-size: var(--text-xs);
line-height: var(--leading-snug);
}
.k-meta-max-3-lines {
width: 100%;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
</style>

View file

@ -0,0 +1,111 @@
<template>
<div class="k-meta">
<div class="k-meta__headline">
<k-headline>{{ headline }}</k-headline>
</div>
<ul>
<li
v-for="item in results"
:key="item.id"
class="k-meta__result"
>
<k-icon
:type="item.icon"
color="orange-600"
/>
<div class="k-meta__result-text">{{ item.text }}</div>
</li>
</ul>
</div>
</template>
<script>
import DescriptionCheck from "./checks/description.js";
const checks = [
DescriptionCheck,
];
export default {
data() {
return {
headline: "Metadata",
};
},
created: function() {
this.load().then((response) => {
this.headline = response.headline;
});
},
computed: {
results() {
const values = this.$store.getters["content/values"]();
return checks.map((v) => {
let item = v.test(values, this);
item.icon = this.icon(item);
item.color = this.color(item);
return item;
});
},
},
methods: {
icon(item) {
if (item.icon) return item.icon;
if (item.status === "success") return "check";
if (item.status === "warn") return "alert";
if (item.status === "info") return "info";
if (item.status === "hint") return "meta-bulb";
return "cancel";
},
color(item) {
if (item.status === "success") return "positive";
if (item.status === "warn") return "orange";
if (item.status === "info") return "blue";
if (item.status === "hint") return "gray";
return "negative";
},
},
};
</script>
<style lang="css">
.k-meta {
background: var(--color-white);
border-radius: var(--rounded-sm);
box-shadow: var(--shadow);
}
.k-meta__headline {
border-bottom: 1px solid var(--color-gray-200);
padding: var(--spacing-2) var(--spacing-3);
}
.k-meta__result {
display: grid;
gap: var(--spacing-3);
grid-template-columns: min-content 1fr;
align-items: start;
padding: var(--spacing-2) var(--spacing-3);
}
.k-meta__result + .k-meta__result {
border-top: 1px solid var(--color-gray-200);
}
.k-meta__result > .k-icon {
position: relative;
top: 2px;
}
.k-meta__result-text {
font-size: var(--text-sm);
line-height: 1.25rem;
}
</style>

View file

@ -0,0 +1,233 @@
<template>
<div class="k-meta-sharing-preview">
<div class="k-meta-sharing-preview__label k-field-label">
<k-icon type="share"/>
<span>{{ headline }}</span>
</div>
<div class="k-meta-sharing-preview__box">
<div
class="k-meta-sharing-preview__image-container"
:data-image-missing="!og_image"
:data-image-missing-text="$t('fabianmichael.meta.og_image.missing')"
>
<img
v-if="og_image"
:src="og_image"
class="k-meta-sharing-preview__preview-image"
/>
<span
v-if="og_image_source"
class="k-meta-sharing-preview__source-badge"
>{{ og_image_source }}</span>
</div>
<div class="k-meta-sharing-preview__content-container">
<span class="k-meta-sharing-preview__site-name">{{ site_name }}</span>
<h2 class="k-meta-sharing-preview__preview-headline">
{{ title }}
</h2>
<p class="k-meta-sharing-preview__preview-paragraph">
{{ description }}
</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
blueprint: String,
lock: [Boolean, Object],
help: String,
name: String,
parent: String,
timestamp: Number
},
data() {
return {
headline: "Basic Meta Information",
metadata_og_image: null,
metadata_og_image_field: null,
page_is_homepage: null,
page_title: null,
page_metadata_description: null,
site_meta_description: null,
site_name: null,
site_og_image: null,
site_title: null,
title_separator: null,
url: null,
og_title_prefix: null,
og_image: null,
og_image_source: null,
};
},
async created() {
const response = await this.load();
this.headline = response.headline;
this.metadata_og_image = response.metadata_og_image;
this.metadata_og_image_field = response.metadata_og_image_field;
this.page_is_homepage = response.page_is_homepage;
this.page_title = response.page_title;
this.page_metadata_description = response.page_metadata_description;
this.site_meta_description = response.site_meta_description;
this.site_name = response.site_name;
this.site_og_image = response.site_og_image;
this.site_title = response.site_title;
this.title_separator = response.title_separator;
this.og_title_prefix = response.og_title_prefix;
this.url = response.url;
this.updateOgImage();
},
computed: {
title() {
const { og_title, meta_title } = this.$store.getters["content/values"]();
const prefix = this.og_title_prefix || "";
const title = this.page_is_homepage
? (og_title || meta_title || this.site_name)
: (og_title || meta_title || this.page_title);
return prefix + title;
},
description() {
const { og_description, meta_description } = this.$store.getters["content/values"]();
return og_description || meta_description || this.page_metadata_description || this.site_meta_description || this.$t("fabianmichael.meta.description_missing");
},
store_image() {
return this.$store.getters["content/values"]().og_image;
},
},
watch: {
store_image: {
handler() {
this.updateOgImage();
},
immediate: true,
},
},
methods: {
load() {
return this.$api.get(this.parent + "/sections/" + this.name);
},
updateOgImage() {
if (this.store_image.length > 0) {
this.$api.files
.get(
this.$store.getters["content/model"]().api,
this.store_image[0].filename,
{ view: "compact", }
).then((response) => {
this.og_image = response.url;
this.og_image_source = this.$t("fabianmichael.meta.source.og_image");
});
} else if (this.metadata_og_image !== null) {
this.og_image = this.metadata_og_image.url;
this.og_image_source = this.$t("fabianmichael.meta.source.metadata");
} else if (this.site_og_image !== null) {
this.og_image = this.site_og_image.url
this.og_image_source = this.$t("fabianmichael.meta.source.site");
} else {
this.og_image = null;
}
},
},
};
</script>
<style lang="css">
.k-meta-sharing-preview__label {
display: flex;
}
.k-meta-sharing-preview__label > * + * {
margin-left: var(--spacing-2);
padding-top: var(--spacing-px);
}
.k-meta-sharing-preview__source-badge {
background: var(--color-gray-900);
color: var(--color-white);
border-radius: var(--rounded-sm);
bottom: var(--spacing-2);
position: absolute;
right: var(--spacing-2);
font-size: .625rem;
line-height: var(--leading-none);
padding: var(--spacing-1) var(--spacing-2);
}
.k-meta-sharing-preview__box {
background: var(--color-white);
border-radius: var(--rounded);
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
max-width: 438px;
overflow: hidden;
position: relative;
width: 100%;
}
.k-meta-sharing-preview__image-container {
background: var(--bg-pattern) var(--color-gray-800);
padding-bottom: 52.25%;
position: relative;
width: 100%;
}
.k-meta-sharing-preview__image-container[data-image-missing]::before {
content: attr(data-image-missing-text);
color: var(--color-white);
position: absolute;
font-size: 1.5em;
top: 50%;
left: 50%;
width: 100%;
text-align: center;
transform: translate(-50%, -50%) rotate(-20deg);
}
.k-meta-sharing-preview__preview-image {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
.k-meta-sharing-preview__content-container {
padding: var(--spacing-2) var(--spacing-3) var(--spacing-3);
}
.k-meta-sharing-preview__site-name {
color: var(--color-gray-600);
font-size: var(--text-xs);
}
.k-meta-sharing-preview__url {
color: var(--color-gray-500);
font-size: var(--text-xs);
margin-top: var(--spacing-3);
}
.k-meta-sharing-preview__preview-headline {
color: var(--color-dark);
font-size: var(--text-base);
line-height: var(--leading-tight);
margin: var(--spacing-1) 0;
padding: 0;
}
.k-meta-sharing-preview__preview-paragraph {
color: var(--color-gray-600);
font-size: var(--text-sm);
line-height: var(--leading-normal);
margin: 0;
padding: 0;
}
</style>

View file

@ -0,0 +1,103 @@
<template>
<k-field
v-bind="$props"
class="k-meta-title-preview"
>
<div class="k-meta-title-preview__content">
<img
alt=""
width="16"
height="16"
class="k-k-meta-title-separator-preview__favicon"
@error="showFavicon = false"
@load="showFavicon = true"
:src="$urls.site + '/favicon.ico'"
:hidden="!showFavicon"
/>
<k-icon
type="globe"
v-if="!showFavicon"
/>
<div class="k-meta-title-preview__title">
<span>{{ title }}</span>
&#32;
<span v-if="!isHomePage" class="k-meta-title-preview__separator">{{ separatorPreview }}</span>
&#32;
<span v-if="!isHomePage">{{ siteTitle }}</span>
</div>
</div>
</k-field>
</template>
<script>
export default {
data() {
return {
showFavicon: false,
};
},
props: {
siteTitle: String,
separator: String,
label: String,
modelTitle: String,
isHomePage: Boolean,
theme: {
default: () => 'field',
type: String,
},
},
computed: {
separatorPreview() {
const values = this.$store.getters["content/values"]();
return values.meta_title_separator || this.separator;
},
title() {
const values = this.$store.getters["content/values"]();
return this.isHomePage
? values.meta_title || this.siteTitle
: values.meta_title || this.modelTitle || this.$t("fabianmichael.meta.page_title.placeholder");
},
},
};
</script>
<style type="css">
.k-meta-title-preview__content {
border: var(--field-input-border);
background: var(--color-gray-300);
border-radius: var(--rounded);
padding: var(--field-input-padding);
min-height: var(--input-height);
display: grid;
align-items: center;
gap: .75ch;
grid-template-columns: min-content 1fr;
}
/**
1. Prevents the icon from collapsing in Kirby 4.0.0-beta.1
*/
.k-k-meta-title-separator-preview__favicon {
border-radius: 2px;
block-size: 1rem; /* 1 */
inline-size: 1rem; /* 1 */
max-inline-size: none; /* 1 */
}
.k-meta-title-preview__title {
overflow: hidden;
text-overflow: ellipsis;
font-size: var(--text-sm);
height: var(--field-input-line-height);
position: relative;
top: .07em;
white-space: nowrap;
padding-block: .1em;
}
</style>

View file

@ -0,0 +1,27 @@
/* global panel */
import "./panel.css";
// import Section from "./components/Section.vue";
import SharePreviewSection from "./components/SharePreviewSection.vue";
import TitlePreviewField from "./components/TitlePreviewField.vue";
import MetaView from "./components/MetaView.vue";
panel.plugin("fabianmichael/meta", {
components: {
"k-meta-view": MetaView,
},
fields: {
"meta-title-preview": TitlePreviewField,
},
sections: {
// meta: Section,
"meta-share-preview": SharePreviewSection,
},
icons: {
"meta-true": '<g fill="currentColor"><polygon points="12.4,6 11,4.6 7,8.6 5,6.6 3.6,8 7,11.4 "></polygon></g>',
"meta-false": '<g fill="currentColor"><polygon points="10.1,4.5 8,6.6 5.9,4.5 4.5,5.9 6.6,8 4.5,10.1 5.9,11.5 8,9.4 10.1,11.5 11.5,10.1 9.4,8 11.5,5.9 "></polygon></g>',
"meta-robot": '<g fill="currentColor"><path d="M10,0v2h2v2H4V2h2V0H0v2h2v2H0v12h16V4h-2V2h2V0H10z M14,14H2V6h2h8h2V14z"></path><rect x="4" y="7" width="3" height="2"></rect><rect x="9" y="7" width="3" height="2"></rect><rect x="5" y="10" width="6" height="3"></rect>',
// "meta-bulb": '<path d="M8,0C4.7,0,2,2.7,2,6c0,2.2,1.2,4.1,3,5.2V15c0,0.6,0.4,1,1,1h4c0.6,0,1-0.4,1-1v-3.8c1.8-1.1,3-3,3-5.2 C14,2.7,11.3,0,8,0z M7,14v-1h2v1H7z M9.6,9.7C9.2,9.8,9,10.2,9,10.6V12H7v-1.4c0-0.4-0.2-0.8-0.6-0.9C4.9,9,4,7.6,4,6 c0-2.2,1.8-4,4-4s4,1.8,4,4C12,7.6,11.1,9,9.6,9.7z"></path>',
}
});

View file

@ -0,0 +1,10 @@
.k-meta-warning-box {
display: block;
background: var(--theme-bg);
color: var(--color-dark);
border-radius: var(--rounded-xs);
line-height: 1.25rem;
margin-top: var(--spacing-4);
border-inline-start: 2px solid var(--theme-light);
padding: .5rem 1.5rem;
}

View file

@ -0,0 +1,9 @@
<title><?= $meta->title()->html() ?></title>
<?php if ($meta->description()->isNotEmpty()): ?>
<meta name="description" content="<?= $meta->description()->html() ?>">
<?php endif ?>
<?php if ($themeColor = \FabianMichael\Meta\Helper::themeColor()): ?>
<meta name="theme-color" content="<?= html($themeColor) ?>">
<?php endif ?>

View file

@ -0,0 +1,20 @@
<?php
$meta = $page->meta();
$data = [
'meta' => $meta,
];
snippet('meta/general', $data);
if ($kirby->option('fabianmichael.meta.robots') !== false) {
snippet('meta/robots', $data);
}
if ($kirby->option('fabianmichael.meta.social') !== false) {
snippet('meta/social', $data);
}
if ($kirby->option('fabianmichael.meta.schema') !== false) {
snippet('meta/schema', $data);
}

View file

@ -0,0 +1,9 @@
<?php if (option('fabianmichael.meta.robots.forceNoIndex')): ?>
<meta name="robots" content="none">
<?php else: ?>
<meta name="robots" content="<?= html($meta->robots()) ?>">
<?php endif ?>
<?php if ($kirby->option('fabianmichael.meta.robots.canonical') !== false): ?>
<link rel="canonical" href="<?= html($meta->canonicalUrl()) ?>">
<?php endif ?>

View file

@ -0,0 +1,5 @@
<?php if (($json = $meta->jsonld()) && empty($json) === false): ?>
<script type="application/ld+json"><?php
echo json_encode($json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | (option('debug') ? JSON_PRETTY_PRINT : 0));
?></script>
<?php endif ?>

View file

@ -0,0 +1,7 @@
<?php
use Kirby\Cms\Html;
foreach ($meta->social() as $tag) {
echo Html::tag('meta', '', $tag) . PHP_EOL;
}

View file

@ -0,0 +1,34 @@
<?php
namespace FabianMichael\Meta;
use Kirby\Cms\App;
class Helper
{
public static function toggleFieldType(): string
{
static $type;
if (! is_null($type)) {
return $type;
}
if (version_compare(App::version(), '3.7.0-rc.1', '>=')) {
return $type = 'toggles';
}
if (App::plugin('fabianmichael/kirby-multi-toggle-field')) {
return $type = 'multi-toggle';
}
return $type = 'select';
}
public static function themeColor(): ?string
{
return kirby()->apply('meta.theme.color', [
'color' => option('fabianmichael.meta.theme.color'),
], 'color');
}
}

View file

@ -0,0 +1,503 @@
<?php
namespace FabianMichael\Meta;
use Kirby\Cms\App as Kirby;
use Kirby\Cms\Field;
use Kirby\Cms\File;
use Kirby\Cms\Language;
use Kirby\Cms\Page;
class PageMeta
{
public const OG_IMAGE_CROP_WIDTH = 1200;
public const OG_IMAGE_CROP_HEIGHT = 630;
protected Page $page;
protected Kirby $kirby;
protected ?string $languageCode;
protected array $metadata = [];
public function __call($name, $arguments): mixed
{
return $this->get(strtolower($name), ...$arguments);
}
protected function __construct(Page $page, ?string $languageCode = null)
{
$this->kirby = $page->kirby();
$this->languageCode = $languageCode;
$this->page = $page;
// Get metadata from page, if possible
if (method_exists($this->page, 'metadata') === true || $this->page->hasMethod('metadata') === true) {
$this->metadata = $this->page->metadata($languageCode);
}
// Allow other plugins/config to alter metadata after load
$this->metadata = $this->kirby->apply(
'meta.load:after',
[
'metadata' => $this->metadata,
'page' => $this->page,
'languageCode' => $this->languageCode,
],
'metadata'
);
}
public function canonicalUrl(): string
{
return $this->meta_canonical_url()
->or($this->metadata('canonical_url'))
->or($this->page->url())
->toString();
}
public function changefreq(): ?string
{
$changefreq = $this->get('sitemap_changefreq', true, true, false);
return $changefreq->isNotEmpty()
? $changefreq->toString()
: null;
}
public function description(): Field
{
return $this->get('meta_description', true, true, false);
}
public function get(
string $key,
bool $metadataFallback = true,
bool $siteFallback = false,
bool $configFallback = false,
mixed $fallback = null
): Field {
// From content file ...
$field = $this->page->content($this->languageCode)->get($key);
if ($field->isNotEmpty() === true) {
return $field;
}
// From page model metadata ...
if ($metadataFallback === true && array_key_exists($key, $this->metadata) === true) {
$value = $this->metadata[$key];
if (is_callable($value) === true) {
$value = $value->call($this->page);
}
return is_a($value, Field::class) === true
? $value
: new Field($this->page, $key, $value);
}
// From site as fallback ...
if ($siteFallback === true) {
$value = $this->page->site()->content($this->languageCode)->get($key);
if ($value->isNotEmpty()) {
return $value;
}
}
// From config as fallback ...
if ($configFallback === true) {
$value = option('fabianmichael.meta.' . str_replace('_', '.', $key));
if ($value !== null) {
return new Field($this->page, $key, $value);
}
}
// Nothing found, return final fallback value
return new Field($this->page, $key, $fallback);
}
public function jsonld(): array
{
$graph = [];
$site = $this->page->site();
$websiteId = url('/#website');
$ownerId = url('/#owner');
// Website
$website = [
'@type' => 'WebSite',
'@id' => $websiteId,
'url' => $site->url(),
'name' => $site->title()->toString(),
'description' => $site->meta_description()->toString(),
];
if ($locale = $this->locale()) {
$website['inLanguage'] = $locale;
}
$graph[] = $website;
// Website owner
$owner = $site->meta_website_owner()->toString();
if ($owner === 'org') {
$org = [
'@type' => 'Organization',
'@id' => $ownerId,
'name' => $site->meta_org_name()->toString(),
'url' => $site->url(),
// 'sameAs' => [
// 'https://example.com',
// ],
];
if ($logo = $site->meta_org_logo()->toFile()) {
$org['logo'] = $logo->url();
}
$graph[] = $org;
} elseif ($owner === 'person' && ($user = $site->meta_person()->toUser())) {
$person = [
'@type' => 'Person',
'@id' => $ownerId,
'name' => $user->name()->toString(),
'email' => $user->email(),
];
if ($avatar = $user->avatar()) {
$person['image'] = $avatar->url();
}
$graph[] = $person;
}
// Merge with page metadata …
$graph = array_merge($graph, $this->metadata('@graph', []));
$json = [
'@context' => 'https://schema.org',
'@graph' => $graph,
];
// Hook
$json = $this->kirby->apply(
'meta.jsonld:after',
[
'json' => $json,
'meta' => $this,
'page' => $this->page,
],
'json'
);
return $json;
}
public function language(): ?Language
{
return empty($this->languageCode) === false
? $this->kirby->language($this->languageCode)
: null;
}
public function languageCode(): ?string
{
return $this->languageCode;
}
public function lastmod()
{
return (int) $this->metadata('lastmod', $this->page->modified('U', 'date'));
}
public function locale(): ?string
{
if ($language = $this->page->kirby()->language()) {
return $language->code();
} elseif ($locale = $this->page->kirby()->option('locale')) {
return preg_replace('/^([^.]+)\:/is', '$1', $locale);
}
return null;
}
public function metadata(string $name, mixed $fallback = null): mixed
{
return array_key_exists($name, $this->metadata) === true
? $this->metadata[$name]
: $fallback;
}
public static function of(Page $page, ?string $languageCode = null): static
{
return new static($page, $languageCode);
}
public function priority(): ?float
{
$priority = $this->get('sitemap_priority', true, true, false, 0.5)->toFloat();
return (float) max(0, min(1, $priority)); // 0 <= value <= 1
}
public function robots(?string $name = null): bool|string
{
if (is_string($name)) {
// single robots value of page as boolean
// if page is a draft, always return false for everything
if (in_array($name, ['index', 'follow']) && $this->page->isDraft()) {
return false;
}
// if page is not in sitemap, it will also not be indexible
if ($name === 'index' && ! Sitemap::isPageIndexible($this->page)) {
return false;
}
// load from content/fallback
return $this
->page
->content($this->languageCode)
->get("robots_{$name}")
->or(SiteMeta::robots($name))
->toBool();
} else {
// robots value for metatag as string|null
$robots = [];
foreach (['index', 'follow', 'archive', 'imageindex', 'snippet', 'translate'] as $prop) {
if ($this->robots($prop) === false) {
$robots[] = "no{$prop}";
}
}
$result = sizeof($robots) > 0
? implode(', ', $robots)
: 'all';
if ($result === 'noindex, nofollow') {
return 'none';
}
return $result;
}
}
public function social(): array
{
$social = [];
$site = $this->page->site();
// OpenGraph
$locale = $this->locale();
if ($locale !== null) {
$social[] = [
'property' => 'og:locale',
'content' => $locale,
];
}
$social[] = [
'property' => 'og:site_name',
'content' => $site->content()->get('og_site_name')
->or($site->title())->toString(),
];
$social[] = [
'property' => 'og:url',
'content' => $this->get('og_url', true)
->or($this->canonicalUrl())->toString(),
];
$social[] = [
'property' => 'og:type',
'content' => 'website', // TODO: make overridable from metadata() method
];
$social[] = [
'property' => 'og:title',
'content' => $this->og_title()->toString(),
];
$description = $this->og_description();
if ($description->isNotEmpty() === true) {
$social[] = [
'property' => 'og:description',
'content' => $description->toString(),
];
}
// Social image
if ($image = $this->og_image()) {
$extension = $image->extension();
if ($image->exists()) {
$thumb = $image->thumb([
'width' => static::OG_IMAGE_CROP_WIDTH,
'height' => static::OG_IMAGE_CROP_HEIGHT,
'crop' => true,
'format' => in_array($extension, ['jpeg', 'jpg', 'png']) === false ? 'jpg' : null,
]);
} else {
$thumb = $image;
}
$social[] = [
'property' => 'og:image',
'content' => $thumb->url(),
];
$social[] = [
'property' => 'og:image:width',
'content' => $thumb->width(),
];
$social[] = [
'property' => 'og:image:height',
'content' => $thumb->height(),
];
if ($image->alt()->isNotEmpty()) {
$social[] = [
'property' => 'og:image:alt',
'content' => $thumb->alt()->toString(),
];
}
}
// Twitter
if (option('fabianmichael.meta.twitter')) {
$social[] = [
'name' => 'twitter:card',
'content' => 'summary_large_image',
];
$twitterSite = $this->get('twitter_site', false, true);
if ($twitterSite->isNotEmpty() === true) {
$social[] = [
'name' => 'twitter:site',
'content' => '@' . ltrim($twitterSite->toString(), '@'),
];
}
$twitterCreator = $this->get('twitter_creator', true, true);
if ($twitterCreator->isNotEmpty() === true) {
$social[] = [
'name' => 'twitter:creator',
'content' => '@' . ltrim($twitterCreator->toString(), '@'),
];
}
}
// Additional metadata from page model
$social = array_merge($social, $this->metadata('@social', []));
// Hook
$social = $this->kirby->apply(
'meta.social:after',
[
'social' => $social,
'meta' => $this,
'page' => $this->page,
],
'social'
);
return $social;
}
public function title(): Field
{
$title = [];
$siteTitle = $this->page->site()->title();
if ($this->page->isHomePage() === true) {
$title[] = $this->page->content($this->languageCode)->get('meta_title')
->or($siteTitle)->toString();
} else {
// TODO: Support pagination
$title[] = $this->page->content($this->languageCode)->get('meta_title')
->or($this->page->title())->toString();
$title[] = SiteMeta::titleSeparator();
$title[] = $siteTitle->toString();
}
return new Field($this->page, 'title', implode(' ', $title));
}
public function og_description(): Field
{
return $this
->get('og_description', true, false)
->or($this->get('meta_description', true, true));
}
public function og_image(bool $fallback = true): ?File
{
// Overrule auto-generated image if custom one is set:
// In content file ...
if ($image = $this->get('og_image', false)->toFile()) {
return $image;
}
// Search in page model ...
if ($image = $this->metadata('og_image')) {
return $image;
}
// Fallback to global thumbnail
if ($fallback === true && ($image = $this->page->site()->content($this->languageCode)->get('og_image')->toFile())) {
return $image;
}
return null;
}
public function og_title(): Field
{
$site = $this->page->site();
$titlePrefix = $this->get(key: 'og_title_prefix', fallback: '');
$title = $this->get('og_title')->or($this->title());
return new Field($this->page, 'og_title', $titlePrefix . $title);
}
public function panelTitlePlaceholder(): string
{
if ($this->page->isHomePage()) {
return $this->page->content($this->languageCode)->get('meta_title')
->or($this->page->site()->title())->toString();
}
return $this->page->title();
}
public function reports(): array
{
$isIndexible = Sitemap::isPageIndexible($this->page) && $this->robots('index');
return [
[
'value' => $isIndexible
? t('fabianmichael.meta.search_engines.visibility.visible')
: t('fabianmichael.meta.search_engines.visibility.hidden'),
'label' => 'fabianmichael.meta.search_engines.visibility.label',
'info' => $isIndexible
? t('fabianmichael.meta.search_engines.visibility.yes')
: t('fabianmichael.meta.search_engines.visibility.no'),
'theme' => $isIndexible ? 'positive' : 'negative',
],
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace FabianMichael\Meta;
class SiteMeta
{
public static function changefreq(): string|null
{
$changefreq = site()
->content()
->get('sitemap_changefreq')
->toString();
return empty($changefreq) === false
? $changefreq
: null;
}
public static function robots(?string $name = null): bool|string|null
{
return site()
->content()
->get("robots_{$name}")
->or(option("fabianmichael.meta.robots.{$name}"))
->toBool();
}
public static function titleSeparator()
{
return site()->meta_title_separator()->or('|')->toString();
}
}

View file

@ -0,0 +1,164 @@
<?php
namespace FabianMichael\Meta;
use DOMDocument;
use DOMElement;
use Kirby\Cms\App;
use Kirby\Cms\Languages;
use Kirby\Cms\Page;
class Sitemap
{
protected App $kirby;
protected bool $isMultilang;
protected Languages $languages;
public function __construct() {
$this->kirby = kirby();
$this->isMultilang = $this->kirby->multilang();
$this->languages = $this->kirby->languages();
}
public static function factory(...$args): static
{
return new static(...$args);
}
public function generate(): string
{
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$root = $doc->createElementNS('http://www.sitemaps.org/schemas/sitemap/0.9', 'urlset');
$root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xhtml', 'http://www.w3.org/1999/xhtml');
// Allow hook to change $doc and $root, e.g. adding namespaces or other attributes.
$this->kirby->trigger('meta.sitemap:before', [
'kirby' => $this->kirby,
'doc' => $doc,
'root' => $root
]);
foreach ($this->kirby->site()->index() as $page) {
$this->urlsForPage($page, $doc, $root);
}
$root = $doc->appendChild($root);
// Allow hook to alter the DOM
$this->kirby->trigger('meta.sitemap:after', [
'kirby' => $this->kirby,
'doc' => $doc,
'root' => $root
]);
return $doc->saveXML();
}
protected function urlsForPage(
Page $page,
DOMDocument $doc,
DOMElement $root): void
{
$meta = $page->meta();
if (static::isPageIndexible($page) === false) {
// Exclude page, if explicitly excluded in page settings
// for global settings
return;
}
$url = $doc->createElement('url');
$url->appendChild($doc->createElement('loc', $page->url()));
if ($this->kirby->option('fabianmichael.meta.sitemap.detailSettings') !== false) {
$priority = $meta->priority();
if ($priority !== null) { // could be 0.0, so has to be checked against NULL
$url->appendChild($doc->createElement('priority', number_format($priority, 1, '.', '')));
}
if ($changefreq = $meta->changefreq()) {
$url->appendChild($doc->createElement('changefreq', $changefreq));
}
}
if ($this->isMultilang && $this->languages->count() > 1) {
// only generate links to translations, if is are more
// than one language defined
foreach ($this->languages as $language) {
$linkEl = $doc->createElement('xhtml:link');
$linkEl->setAttribute('rel', 'alternate');
$linkEl->setAttribute('hreflang', $code = $language->code());
$linkEl->setAttribute('href', $page->url($code));
$url->appendChild($linkEl);
}
}
// Add lastmod date either from metadata or from modified date of page
$url->appendChild($doc->createElement('lastmod', date('Y-m-d', $meta->lastmod())));
// Allow hook to alter the DOM
if ($this->kirby->apply('meta.sitemap.url', [
'kirby' => $this->kirby,
'page' => $page,
'meta' => $meta,
'doc' => $doc,
'url' => $url,
'include' => true,
], 'include') !== false) {
$root->appendChild($url);
}
}
public static function isPageIndexible(Page $page): bool
{
// pages have to pass a set of for being indexible. If any test
// fails, the page is excluded from index
$templatesExclude = option('fabianmichael.meta.sitemap.templates.exclude', []);
$templatesExcludeRegex = '!^(?:' . implode('|', $templatesExclude) . ')$!i';
$templatesIncludeUnlisted = option('fabianmichael.meta.sitemap.templates.includeUnlisted', []);
$templatesIncludeUnlistedRegex = '!^(?:' . implode('|', $templatesIncludeUnlisted) . ')$!i';
$pagesExclude = option('fabianmichael.meta.sitemap.pages.exclude', []);
$pagesExcludeRegex = '!^(?:' . implode('|', $pagesExclude) . ')$!i';
$pagesIncludeUnlisted = option('fabianmichael.meta.sitemap.pages.includeUnlisted', []);
$pagesIncludeUnlistedRegex = '!^(?:' . implode('|', $pagesIncludeUnlisted) . ')$!i';
if ($page->isErrorPage()) {
// error page is always excluded from sitemap
return false;
}
if (! $page->isHomePage() && $page->status() === 'unlisted') {
if (preg_match($templatesIncludeUnlistedRegex, $page->intendedTemplate()->name()) !== 1
&& preg_match($pagesIncludeUnlistedRegex, $page->id()) !== 1) {
// unlisted pages are only indexible, if exceptions are
// defined for them based on page id or template
return false;
}
}
if (preg_match($templatesExcludeRegex, $page->intendedTemplate()->name()) === 1) {
// page is in exclude-list of templates
return false;
}
if (preg_match($pagesExcludeRegex, $page->id()) === 1) {
// page is in exclude-list of page IDs
return false;
}
if (! is_null($page->parent())) {
// test indexability of parent pages as well
return static::isPageIndexible($page->parent());
}
return true;
}
}

View file

@ -0,0 +1,10 @@
<?php
namespace FabianMichael\Meta;
use Kirby\Cms\Page;
class SitemapPage extends Page
{
}

View file

@ -0,0 +1,8 @@
<?php
use Kirby\Toolkit\Html;
// this template needs to exists, because otherwise content
// representations do not work properly (tested with Kirby v3.9.2)
echo Html::link($page->url() . '.xml', $page->title());

View file

@ -0,0 +1,10 @@
<?php
$kirby->response()->type('application/xml');
echo FabianMichael\Meta\Sitemap::factory()->generate();
if ($kirby->option('cache.page.active') && $kirby->option('cache.page.type') === 'static') {
echo PHP_EOL;
echo '<!-- static ' . date('c') . ' -->';
}

View file

@ -0,0 +1,111 @@
<?php
return [
'fabianmichael.meta.tab.label' => 'Metadata (SEO)',
'fabianmichael.meta.page_title.placeholder' => 'Sidetitel',
'fabianmichael.meta.title_preview.label' => 'Titel forhåndsvisning',
'fabianmichael.meta.global_settings.headline' => ' Globale indstillinger',
'fabianmichael.meta.global_general.headline' => 'Generelle indstillinger',
'fabianmichael.meta.general.headline' => 'Grundlæggende meta information',
'fabianmichael.meta.title.label' => 'Titel (Tilsidesæt)',
'fabianmichael.meta.title.help' => 'Sidens titel som den skal vises på søgemaskiner. Hvis dette felt er tomt, vil Kirby sidens titel blive brugt som standard.',
'fabianmichael.meta.title_separator.label' => 'Titel Separator',
'fabianmichael.meta.title_separator.help' => 'Separator der vises mellem side og webstedets titel.',
'fabianmichael.meta.robots.headline' => 'Søgemaskiner',
'fabianmichael.meta.robots.help' => 'Detaljerede instruktioner til hvordan søgemaskiner skal håndtere denne side.',
'fabianmichael.meta.robots_index.label' => 'Indeksering',
'fabianmichael.meta.robots_index.help' => 'Søgemaskiner må indeksere denne side.',
'fabianmichael.meta.robots_follow.label' => 'Følg links',
'fabianmichael.meta.robots_follow.help' => 'Søgemaskiner vil følge links på denne side.',
'fabianmichael.meta.robots_archive.label' => 'Arkivering',
'fabianmichael.meta.robots_archive.help' => 'Søgemaskiner vil gemme denne side i cache.',
'fabianmichael.meta.robots_imageindex.label' => 'Billedindeksering',
'fabianmichael.meta.robots_imageindex.help' => 'Søgemaskiner vil associere denne side med billedsøgeresultater.',
'fabianmichael.meta.robots_snippet.label' => 'Uddrag',
'fabianmichael.meta.robots_snippet.help' => 'Søgemaskiner vil vise beskrivelsesuddrag for denne side.',
'fabianmichael.meta.global_robots.headline' => 'Søgemaskine indstillinger',
'fabianmichael.meta.global_robots.help' => 'Detaljerede instruktioner til hvordan søgemaskiner skal håndtere sider på dette websted som standard. Sider kan have individuelle indstillinger for at tilsidesætte disse standarder.',
'fabianmichael.meta.global_robots_index.label' => 'Indeksering',
'fabianmichael.meta.global_robots_index.help' => 'Søgemaskiner må indeksere dette websted.',
'fabianmichael.meta.global_robots_follow.label' => 'Følg links',
'fabianmichael.meta.global_robots_follow.help' => 'Søgemaskiner vil følge links på dette websted.',
'fabianmichael.meta.global_robots_archive.label' => 'Arkivering',
'fabianmichael.meta.global_robots_archive.help' => 'Søgemaskiner vil gemme sider på dette websted i cache.',
'fabianmichael.meta.global_robots_imageindex.label' => 'Billedindeksering',
'fabianmichael.meta.global_robots_imageindex.help' => 'Søgemaskiner vil associere sider med billedsøgeresultater.',
'fabianmichael.meta.global_robots_snippet.label' => 'Uddrag',
'fabianmichael.meta.global_robots_snippet.help' => 'Søgemaskiner vil vise beskrivelsesuddrag for sider.',
'fabianmichael.meta.description.label' => 'Beskrivelse',
'fabianmichael.meta.description.help' => 'En kort beskrivelse af siden der vil blive vist under sidens titel af søgemaskiner.',
'fabianmichael.meta.global_description.help' => 'Den globale beskrivelse vil blive brugt som fallback for alle sider, der ikke har en dedikeret beskrivelse.',
'fabianmichael.meta.canonical_url.label' => 'Kanonisk URL',
'fabianmichael.meta.canonical_url.help' => 'Sidenes kanoniske URL. Hvis dette felt er tomt, vil sidens URL blive brugt som standard.',
'fabianmichael.meta.global_default_value.label' => 'Websted ({ tilstand })',
'fabianmichael.meta.config_default_value.label' => 'Konfiguration ({ tilstand })',
'fabianmichael.meta.state.on' => 'tændt',
'fabianmichael.meta.state.off' => 'slukket',
'fabianmichael.meta.state.unset' => 'ikke indstillet',
'fabianmichael.meta.og.headline' => 'Deling på sociale medier',
'fabianmichael.meta.og.help' => '[Open Graph](https://ogp.me/) metadata bruges af sociale netværk (f.eks. Facebook, Twitter) og de fleste beskedapps (f.eks. Signal, Telegram, iMessage).',
'fabianmichael.meta.og_site_name.label' => 'Del webstedets navn',
'fabianmichael.meta.og_site_name.help' => 'Navnet der skal vises for hele webstedet til deling på sociale medier. Hvis ikke indstillet, vil webstedets titel blive brugt som fallback.',
'fabianmichael.meta.global_og_image.label' => 'Standard delingsbillede',
'fabianmichael.meta.global_og_image.help' => 'Et billede der skal repræsentere dine delte links på sociale medier og apps. Billedet vil automatisk blive beskåret. Dette globale billede bruges som fallback for sider der ikke har et dedikeret billede.<br><br>**Anbefalet størrelse:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Formater:** JPEG, PNG, GIF, WebP, AVIF',
'fabianmichael.meta.og_image.label' => 'Delingsbillede',
'fabianmichael.meta.og_image.help' => 'Et billede der skal repræsentere dine delte links på sociale medier og apps. Billedet vil automatisk blive beskåret. Det globale fallback-billede vil blive brugt som fallback.<br><br>**Anbefalet størrelse:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Formater:** JPEG, PNG, GIF, WebP, AVIF {< site.metaPanelWarning("no_og_image_fallback") >}',
'fabianmichael.meta.og_title.label' => 'Delingstitel (tilsidesæt)',
'fabianmichael.meta.og_title.help' => 'Sidens titel som den vil blive vist ved deling. Hvis ikke indstillet, vil både **Titel (Tilsidesæt)** og sidens titel blive brugt som fallback.',
'fabianmichael.meta.og_description.label' => 'Delingsbeskrivelse',
'fabianmichael.meta.og_description.help' => 'En en til to sætningers beskrivelse af objektet. Sidens beskrivelse og webstedets beskrivelse vil blive brugt som fallbacks.',
'fabianmichael.meta.image.empty' => 'Ingen billede valgt endnu',
'fabianmichael.meta.files.headline' => 'Filer',
'fabianmichael.meta.sitemap.priority.label' => 'Sitemap prioritet',
'fabianmichael.meta.sitemap.priority.help' => 'Relativ prioritet i forhold til andre sider på dit websted.',
'fabianmichael.meta.sitemap.global_priority.help' => 'Standard prioritet for alle sider på dette websted. At indstille en prioritet giver en indikation til søgemaskiner om den relative vigtighed af dine sider i forhold til hinanden.',
'fabianmichael.meta.sitemap.changefreq.label' => 'Ændringsfrekvens',
'fabianmichael.meta.sitemap.changefreq.help' => 'Fortæller søgemaskiner hvor ofte indholdet ændrer sig.',
'fabianmichael.meta.sitemap.changefreq.always' => 'Altid',
'fabianmichael.meta.sitemap.changefreq.hourly' => 'Hver time',
'fabianmichael.meta.sitemap.changefreq.daily' => 'Dagligt',
'fabianmichael.meta.sitemap.changefreq.weekly' => 'Ugentligt',
'fabianmichael.meta.sitemap.changefreq.monthly' => 'Månedligt',
'fabianmichael.meta.sitemap.changefreq.yearly' => 'Årligt',
'fabianmichael.meta.sitemap.changefreq.never' => 'Aldrig',
'fabianmichael.meta.twitter.headline' => 'Twitter',
'fabianmichael.meta.twitter.site.label' => 'Twitter brugernavn for webstedet',
'fabianmichael.meta.twitter.creator.label' => 'Twitter brugernavn for indholdsopretter',
'fabianmichael.meta.no_og_image_fallback' => 'Intet globalt fallback-billede defineret. Gå til <a href="{ link }">globale metadata indstillinger</a> og upload et.',
'fabianmichael.meta.schema.person_privacy_notice.label' => 'Privatlivsmeddelelse',
'fabianmichael.meta.schema.person_privacy_notice.text' => 'Ved at vælge en bruger vil du eksponere personlige oplysninger som e-mailadresse og profilbillede for søgemaskiner, andre webcrawler og alle der læser kildekoden på din hjemmeside.',
'fabianmichael.meta.sharing_preview.headline' => 'Del forhåndsvisning',
'fabianmichael.meta.description_missing' => '[Delingsbeskrivelse og fallback-beskrivelse mangler]',
'fabianmichael.meta.source.og_image' => 'Kilde: Delingsbillede',
'fabianmichael.meta.source.metadata' => 'Kilde: Side miniaturebillede',
'fabianmichael.meta.source.site' => 'Kilde: Fallback miniaturebillede',
'fabianmichael.meta.og_image.missing' => 'Billede mangler',
'fabianmichael.meta.schema.headline' => 'Strukturerede data',
'fabianmichael.meta.schema.help' => 'Disse data er baseret på [Schema.org](https://schema.org) standarden og kan opfanges af søgemaskiner som [Googles](https://google.com) videngrafik for en bedre forståelse af din organisation eller person.',
'fabianmichael.meta.schema.website_owner.label' => 'Webstedsejer',
'fabianmichael.meta.schema.website_owner.help' => 'Vælg om dit websted repræsenterer en organisation eller enkeltperson.',
'fabianmichael.meta.schema.org_name.label' => 'Organisationsnavn',
'fabianmichael.meta.schema.org_logo.label' => 'Organisationslogo',
'fabianmichael.meta.schema.meta_person.label' => 'Person',
'fabianmichael.meta.schema.meta_person.empty' => 'Ingen bruger valgt endnu',
'fabianmichael.meta.schema.meta_person.help' => 'Vælg en bruger der repræsenterer dette websted.',
'fabianmichael.meta.status.label' => 'Status',
'fabianmichael.meta.search_engines.visibility.visible' => 'Synlig',
'fabianmichael.meta.search_engines.visibility.hidden' => 'Skjult',
'fabianmichael.meta.search_engines.visibility.label' => 'Søgemaskine synlighed',
'fabianmichael.meta.search_engines.visibility.yes' => 'Denne side indekseres af søgemaskiner og kan vises i søgeresultaterne',
'fabianmichael.meta.search_engines.visibility.no' => 'Denne side er skjult fra søgeresultaterne',
];

View file

@ -0,0 +1,112 @@
<?php
return [
'fabianmichael.meta.tab.label' => 'Metadaten (SEO)',
'fabianmichael.meta.page_title.placeholder' => 'Seitentitel',
'fabianmichael.meta.title_preview.label' => 'Titel (Vorschau)',
'fabianmichael.meta.global_settings.headline' => 'Globale Einstellungen',
'fabianmichael.meta.global_general.headline' => 'Allgemein',
'fabianmichael.meta.general.headline' => 'Basisdaten',
'fabianmichael.meta.title.label' => 'Titel (Überschreiben)',
'fabianmichael.meta.title.help' => 'Der Seitentitel, so wie er in Suchmaschinen erscheinen soll. Wenn das Feld leer ist, wird stattdessen der Seitentitel ausgegeben.',
'fabianmichael.meta.title_separator.label' => 'Titel-Trennzeichen',
'fabianmichael.meta.title_separator.help' => 'Das Trennzeichen wird zwischen dem Titel der aktuellen Seite und dem Titel der Website angezeigt.',
'fabianmichael.meta.robots.headline' => 'Suchmaschinen',
'fabianmichael.meta.robots.help' => 'Detaillierte Anweisungen, wie Suchmaschinen mit dieser Seite umgehen sollen.',
'fabianmichael.meta.robots_index.label' => 'Indizieren',
'fabianmichael.meta.robots_index.help' => 'Suchmaschinen werden diese Seite indizieren.',
'fabianmichael.meta.robots_follow.label' => 'Links folgen',
'fabianmichael.meta.robots_follow.help' => 'Suchmaschinen werden Links auf dieser Seite folgen.',
'fabianmichael.meta.robots_archive.label' => 'Archivierung',
'fabianmichael.meta.robots_archive.help' => 'Suchmaschinen dürfen zwischengespeicherte Versionen ausliefern.',
'fabianmichael.meta.robots_imageindex.label' => 'Bild-Indexierung',
'fabianmichael.meta.robots_imageindex.help' => 'Bilder auf dieser Seite erscheinen in der Bildsuche.',
'fabianmichael.meta.robots_snippet.label' => 'Snippets',
'fabianmichael.meta.robots_snippet.help' => 'Suchmaschinen dürfen Textschnipsel aus dieser Seite generieren.',
'fabianmichael.meta.global_robots.headline' => 'Suchmaschinen-Einstellungen',
'fabianmichael.meta.global_robots.help' => 'Standard-Einstellungen für Anweisungen an Suchmaschinen, in welcher Weise sie Seiten dieser Website indizieren dürfen. Seiten können individuelle Einstellungen verwenden, um dieses Verhaltern zu überschreiben.',
'fabianmichael.meta.global_robots_index.label' => 'Indexierung',
'fabianmichael.meta.global_robots_index.help' => 'Suchmaschinen werden diese Website indizieren.',
'fabianmichael.meta.global_robots_follow.label' => 'Links folgen',
'fabianmichael.meta.global_robots_follow.help' => 'Suchmaschinen werden Verlinkungen auf dieser Website folgen.',
'fabianmichael.meta.global_robots_archive.label' => 'Archivierung',
'fabianmichael.meta.global_robots_archive.help' => 'Suchmaschinen dürfen zwischengespeicherte Versionen ausliefern.',
'fabianmichael.meta.global_robots_imageindex.label' => 'Bild-Indexierung',
'fabianmichael.meta.global_robots_imageindex.help' => 'Bilder auf dieser Website erscheinen in der Bildsuche.',
'fabianmichael.meta.global_robots_snippet.label' => 'Snippets',
'fabianmichael.meta.global_robots_snippet.help' => 'Suchmaschinen dürfen Textschnipsel aus dieser Website generieren.',
'fabianmichael.meta.description.label' => 'Beschreibung',
'fabianmichael.meta.description.help' => 'Eine kurze Beschreibung, die Suchmachinen in den Ergebnissen unterhalb des Seitentitels darstellen.',
'fabianmichael.meta.global_description.help' => 'Die globale Beschreibung wird als Standard für alle Unterseiten verwendet, die keine eigene Beschreibung haben.',
'fabianmichael.meta.canonical_url.label' => 'Eindeutige URL',
'fabianmichael.meta.canonical_url.help' => 'Eindeutige URL zu dieser Seite. Standardmäßig wird die normale URL verwendet, falls dieses Feld leer ist.',
'fabianmichael.meta.global_default_value.label' => 'Global ({ state })',
'fabianmichael.meta.config_default_value.label' => 'Konfiguration ({ state })',
'fabianmichael.meta.state.on' => 'ja',
'fabianmichael.meta.state.off' => 'nein',
'fabianmichael.meta.state.unset' => 'nicht gesetzt',
'fabianmichael.meta.og.headline' => 'Teilen in sozialen Medien',
'fabianmichael.meta.og.help' => '[Open Graph](https://ogp.me/) wird von sozialen Netzwerken und den Messenger-Apps verwendet, um Vorschauen für Links zu generieren.',
'fabianmichael.meta.og_site_name.label' => 'Titel der Website für Teilen',
'fabianmichael.meta.og_site_name.help' => 'Der Website-Titel, welcher beim Teilen verwendet werden soll. Standardmäßig wird der Titel der Website verwendet.',
'fabianmichael.meta.global_og_image.label' => 'Standard Bild für Teilen',
'fabianmichael.meta.global_og_image.help' => 'Ein Bild, welches diese Website beim Teilen in sozialen Netzwerken und Messegern repräsentiert. Wird automatisch zugeschnitten. Dieses Bild wird als Standard für Seiten verwendet, die kein eigenes Bild haben.<br><br>**Empfohlene Größe:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Erlaubte Formate:** JPEG, PNG, GIF, WebP, AVIF',
'fabianmichael.meta.og_image.label' => 'Bild für Teilen',
'fabianmichael.meta.og_image.help' => 'Ein Bild, welches diese Seite beim Teilen in sozialen Netzwerken und Messegern repräsentiert. Wird automatisch zugeschnitten. Wenn kein Bild ausgewählt ist, wird das globale Standard-Bild verwendet.<br><br>**Empfohlene Größe:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Erlaubte Formate:** JPEG, PNG, GIF, WebP, AVIF {< site.metaPanelWarning("no_og_image_fallback") >}',
'fabianmichael.meta.og_title.label' => 'Gesonderter Titel für Teilen',
'fabianmichael.meta.og_title.help' => 'Der Titel dieser Seite beim Teilen in sozialen Netzwerken. Verwendet **Title (überschreiben)** oder den Seitentitel als Alternativen.',
'fabianmichael.meta.og_description.label' => 'Beschreibung für Teilen',
'fabianmichael.meta.og_description.help' => 'Eine kurze Beschreibung von ein oder zwei Zeilen, die beim Teilen in sozialen Netzwerken als Vorschau angezeigt wird. Verwendet Beschreibungen der Seite oder Website als Alternativen.',
'fabianmichael.meta.image.empty' => 'Noch kein Bild gewählt',
'fabianmichael.meta.files.headline' => 'Dateien',
'fabianmichael.meta.sitemap.priority.label' => 'Sitemap-Proprität',
'fabianmichael.meta.sitemap.priority.help' => 'Relative Priorität im Vergleich zu anderen Seiten dieser Website.',
'fabianmichael.meta.sitemap.global_priority.help' => 'Standard-Priorität für Seiten. Eine Priorisierung zu definieren kann Suchmaschinen dabei helfen, die Wichtigkeit einzelner Seiten zu ermitteln.',
'fabianmichael.meta.sitemap.changefreq.label' => 'Änderungsfrequenz',
'fabianmichael.meta.sitemap.changefreq.help' => 'Gib Suchmaschinen Informationen darüber, wie oft sich Inhalte ändern.',
'fabianmichael.meta.sitemap.changefreq.always' => 'Ständig',
'fabianmichael.meta.sitemap.changefreq.hourly' => 'Stündlich',
'fabianmichael.meta.sitemap.changefreq.daily' => 'Täglich',
'fabianmichael.meta.sitemap.changefreq.weekly' => 'Wöchentlich',
'fabianmichael.meta.sitemap.changefreq.monthly' => 'Monatlich',
'fabianmichael.meta.sitemap.changefreq.yearly' => 'Jährlich',
'fabianmichael.meta.sitemap.changefreq.never' => 'Niemals',
'fabianmichael.meta.twitter.headline' => 'Twitter',
'fabianmichael.meta.twitter.site.label' => 'Twitter-Benutzername der Website',
'fabianmichael.meta.twitter.creator.label' => 'Twitter-Benutzername des Authors',
'fabianmichael.meta.no_og_image_fallback' => 'Kein globales "Teilen"-Bild definiert. Ein solches Bild sollte in den <a href="{ link }">globalen Einstellungen</a> hochgeladen werden.',
'fabianmichael.meta.schema.person_privacy_notice.label' => 'Hinweis zum Datenschutz',
'fabianmichael.meta.schema.person_privacy_notice.text' => 'Durch das Auswählen eines Benutzer*innen-Account werden private Informationen wie die E-Mailadresse und das Profilbild in mit Suchmaschinen und alllen Menschen und Bots, die den Quelltext der Website lesen geteilt.',
'fabianmichael.meta.sharing_preview.headline' => 'Vorschau für Teilen',
'fabianmichael.meta.description_missing' => '[Beschreibung für Teilen und globale Beschreibung fehlen]',
'fabianmichael.meta.source.og_image' => 'Quelle: Bild für Teilen',
'fabianmichael.meta.source.metadata' => 'Quelle: Seiten-Thumbnail',
'fabianmichael.meta.source.site' => 'Quelle: globale Standard-Thumbnail',
'fabianmichael.meta.og_image.missing' => 'Bild fehlt',
'fabianmichael.meta.schema.headline' => 'Strukturierte Daten',
'fabianmichael.meta.schema.help' => 'Diese Daten basieren auf dem [Schema.org](https://schema.org)-Standard und werden von Suchmachhinen wie [Google](https://google.com) verwendet, um Zusammmenhänge zwischen Daten, Organisationen und Personen besser verstehen zu können.',
'fabianmichael.meta.schema.website_owner.label' => 'Eigentümer:in der Website',
'fabianmichael.meta.schema.website_owner.help' => 'Wählen Sie, ob diese Website eine Person oder Organisation repräsentiert.',
'fabianmichael.meta.schema.org_name.label' => 'Name der Organisation',
'fabianmichael.meta.schema.org_logo.label' => 'Logo der Organisation',
'fabianmichael.meta.schema.meta_person.label' => 'Person',
'fabianmichael.meta.schema.meta_person.empty' => 'Kein Benutzer*innen-Account ausgewählt',
'fabianmichael.meta.schema.meta_person.help' => 'Wählen Sie einen Benutzer*innen-Account, welcher diese Website repräsentiert.',
'fabianmichael.meta.status.label' => 'Status',
'fabianmichael.meta.search_engines.visibility.visible' => 'Sichtbar',
'fabianmichael.meta.search_engines.visibility.hidden' => 'Versteckt',
'fabianmichael.meta.search_engines.visibility.label' => 'Sichtbarkeit in Suchmaschinen',
'fabianmichael.meta.search_engines.visibility.yes' => 'Diese Seite wird von Suchmaschinen indexizert und kann in Suchergebnissen erscheinen',
'fabianmichael.meta.search_engines.visibility.no' => 'Diese Seite wird in den Suchergebnissen versteckt',
];

View file

@ -0,0 +1,111 @@
<?php
return [
'fabianmichael.meta.tab.label' => 'Metadata (SEO)',
'fabianmichael.meta.page_title.placeholder' => 'Page title',
'fabianmichael.meta.title_preview.label' => 'Title preview',
'fabianmichael.meta.global_settings.headline' => 'Global settings',
'fabianmichael.meta.global_general.headline' => 'General settings',
'fabianmichael.meta.general.headline' => 'Basic meta information',
'fabianmichael.meta.title.label' => 'Title (Override)',
'fabianmichael.meta.title.help' => 'The page title as it should be displayed on search engines. Will default to Kirby page title when this field is empty.',
'fabianmichael.meta.title_separator.label' => 'Title Separator',
'fabianmichael.meta.title_separator.help' => 'Separator to be displayed between page and site title.',
'fabianmichael.meta.robots.headline' => 'Search engines',
'fabianmichael.meta.robots.help' => 'Detailed instructions for how search engines should handle this page.',
'fabianmichael.meta.robots_index.label' => 'Indexing',
'fabianmichael.meta.robots_index.help' => 'Search engines are allowed to index this page.',
'fabianmichael.meta.robots_follow.label' => 'Follow links',
'fabianmichael.meta.robots_follow.help' => 'Search engines will follow links on this page.',
'fabianmichael.meta.robots_archive.label' => 'Archiving',
'fabianmichael.meta.robots_archive.help' => 'Search engines will cache this page.',
'fabianmichael.meta.robots_imageindex.label' => 'Image indexing',
'fabianmichael.meta.robots_imageindex.help' => 'Search engines will associate this page with image search results.',
'fabianmichael.meta.robots_snippet.label' => 'Snippets',
'fabianmichael.meta.robots_snippet.help' => 'Search engines will display description snippets for this page.',
'fabianmichael.meta.global_robots.headline' => 'Search engine settings',
'fabianmichael.meta.global_robots.help' => 'Detailed instructions for how search engines should handle pages of this site by default. Pages can have their individual settings to override these defaults.',
'fabianmichael.meta.global_robots_index.label' => 'Indexing',
'fabianmichael.meta.global_robots_index.help' => 'Search engines are allowed to index this site.',
'fabianmichael.meta.global_robots_follow.label' => 'Follow links',
'fabianmichael.meta.global_robots_follow.help' => 'Search engines will follow links on this site.',
'fabianmichael.meta.global_robots_archive.label' => 'Archiving',
'fabianmichael.meta.global_robots_archive.help' => 'Search engines will cache pages on this site.',
'fabianmichael.meta.global_robots_imageindex.label' => 'Image indexing',
'fabianmichael.meta.global_robots_imageindex.help' => 'Search engines will associate pages with image search results.',
'fabianmichael.meta.global_robots_snippet.label' => 'Snippets',
'fabianmichael.meta.global_robots_snippet.help' => 'Search engines will display description snippets for pages.',
'fabianmichael.meta.description.label' => 'Description',
'fabianmichael.meta.description.help' => 'A short description of the page that will be displayed underneath the page title by search engines.',
'fabianmichael.meta.global_description.help' => 'The global description will be used as fallback for all pages, that dont have a dedicated description.',
'fabianmichael.meta.canonical_url.label' => 'Canonical URL',
'fabianmichael.meta.canonical_url.help' => 'The canonical URL of the page. Will default to page URL when this field is empty.',
'fabianmichael.meta.global_default_value.label' => 'Site ({ state })',
'fabianmichael.meta.config_default_value.label' => 'Config ({ state })',
'fabianmichael.meta.state.on' => 'on',
'fabianmichael.meta.state.off' => 'off',
'fabianmichael.meta.state.unset' => 'not set',
'fabianmichael.meta.og.headline' => 'Social media sharing',
'fabianmichael.meta.og.help' => '[Open Graph](https://ogp.me/) metadata is consumed by social networks (e.g. Facebook, Twitter) and most messenger apps (e.g. Signal, Telegram, iMessage).',
'fabianmichael.meta.og_site_name.label' => 'Share site name',
'fabianmichael.meta.og_site_name.help' => 'The name which should be displayed for the overall site for social media sharing. Will use site title as fallback.',
'fabianmichael.meta.global_og_image.label' => 'Default share image',
'fabianmichael.meta.global_og_image.help' => 'An image which should represent your shared links within social media websites and apps. Will be cropped automatically. This global image is used as a fallback for pages, that do not have a dedicated image.<br><br>**Recommended size:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Formats:** JPEG, PNG, GIF, WebP, AVIF',
'fabianmichael.meta.og_image.label' => 'Share Image',
'fabianmichael.meta.og_image.help' => 'An image which should represent your shared links within social media websites and apps. Will be cropped automatically. Will use the globally defined fallback image as fallback.<br><br>**Recommended size:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Formats:** JPEG, PNG, GIF, WebP, AVIF {< site.metaPanelWarning("no_og_image_fallback") >}',
'fabianmichael.meta.og_title.label' => 'Share title (override)',
'fabianmichael.meta.og_title.help' => 'The title of your page as it should appear when shared. Will use **Title (override)** and page title as fallback.',
'fabianmichael.meta.og_description.label' => 'Share description',
'fabianmichael.meta.og_description.help' => 'A one to two sentence description of your object. Will use page description and site description as fallbacks.',
'fabianmichael.meta.image.empty' => 'No image selected yet',
'fabianmichael.meta.files.headline' => 'Files',
'fabianmichael.meta.sitemap.priority.label' => 'Sitemap priority',
'fabianmichael.meta.sitemap.priority.help' => 'Relative priority compared to other pages on your site.',
'fabianmichael.meta.sitemap.global_priority.help' => 'Default priority for all pages of this site. Setting a priority gives a hint to search engines about the relative importance of your pages in comparison to each other.',
'fabianmichael.meta.sitemap.changefreq.label' => 'Change frequency',
'fabianmichael.meta.sitemap.changefreq.help' => 'Tells search engines, how often the content changes.',
'fabianmichael.meta.sitemap.changefreq.always' => 'Always',
'fabianmichael.meta.sitemap.changefreq.hourly' => 'Hourly',
'fabianmichael.meta.sitemap.changefreq.daily' => 'Daily',
'fabianmichael.meta.sitemap.changefreq.weekly' => 'Weekly',
'fabianmichael.meta.sitemap.changefreq.monthly' => 'Monthly',
'fabianmichael.meta.sitemap.changefreq.yearly' => 'Yearly',
'fabianmichael.meta.sitemap.changefreq.never' => 'Never',
'fabianmichael.meta.twitter.headline' => 'Twitter',
'fabianmichael.meta.twitter.site.label' => 'Twitter username of website',
'fabianmichael.meta.twitter.creator.label' => 'Twitter username of content creator',
'fabianmichael.meta.no_og_image_fallback' => 'No global fallback image defined. Please go to <a href="{ link }">global metadata settings</a> and upload one.',
'fabianmichael.meta.schema.person_privacy_notice.label' => 'Privacy notice',
'fabianmichael.meta.schema.person_privacy_notice.text' => 'By selecting a user, you will expose personal information such as the email address and profile image to search engines, other crawlers and everyone who reads the source code of your website.',
'fabianmichael.meta.sharing_preview.headline' => 'Share preview',
'fabianmichael.meta.description_missing' => '[Share Description and fallback Description Missing]',
'fabianmichael.meta.source.og_image' => 'Source: Share Image',
'fabianmichael.meta.source.metadata' => 'Source: Page thumbnail',
'fabianmichael.meta.source.site' => 'Source: Fallback thumbnail',
'fabianmichael.meta.og_image.missing' => 'Image missing',
'fabianmichael.meta.schema.headline' => 'Structured data',
'fabianmichael.meta.schema.help' => 'This data is based on the [Schema.org](https://schema.org) standard and can be picked up by search engines such as [Google](https://google.com)s knowledge graph for better understanging your organization or person.',
'fabianmichael.meta.schema.website_owner.label' => 'Website owner',
'fabianmichael.meta.schema.website_owner.help' => 'Select wether your website represents an organisation or individual person.',
'fabianmichael.meta.schema.org_name.label' => 'Organization name',
'fabianmichael.meta.schema.org_logo.label' => 'Organization logo',
'fabianmichael.meta.schema.meta_person.label' => 'Person',
'fabianmichael.meta.schema.meta_person.empty' => 'No user selected yet',
'fabianmichael.meta.schema.meta_person.help' => 'Select a user who represents this website.',
'fabianmichael.meta.status.label' => 'Status',
'fabianmichael.meta.search_engines.visibility.visible' => 'Visible',
'fabianmichael.meta.search_engines.visibility.hidden' => 'Hidden',
'fabianmichael.meta.search_engines.visibility.label' => 'Search engine visbility',
'fabianmichael.meta.search_engines.visibility.yes' => 'This page is indexed by search engines and may appear in search results',
'fabianmichael.meta.search_engines.visibility.no' => 'This page is hidden from search results',
];

View file

@ -0,0 +1,115 @@
<?php
return [
'fabianmichael.meta.tab.label' => 'Métadonnées (SEO)',
'fabianmichael.meta.page_title.placeholder' => 'Titre de la page',
'fabianmichael.meta.title_preview.label' => 'Aperçu du titre',
'fabianmichael.meta.global_settings.headline' => 'Paramètres globaux',
'fabianmichael.meta.global_general.headline' => 'Paramètres généraux',
'fabianmichael.meta.general.headline' => 'Informations méta de base',
'fabianmichael.meta.title.label' => 'Titre (Forcé)',
'fabianmichael.meta.title.help' => 'Le titre de la page tel qu\'il sera affiché pour les moteurs de recherche. Il sera remplacé par le titre de la page si ce champ reste vide.',
'fabianmichael.meta.title_separator.label' => 'Séparateur du titre',
'fabianmichael.meta.title_separator.help' => 'La séparateur s\'affiche entre le titre de la page et du site.',
'fabianmichael.meta.robots.headline' => 'Moteurs de recherche',
'fabianmichael.meta.robots.help' => 'Informations détaillées sur comment les moteurs de recherche traitent cette page.',
'fabianmichael.meta.robots_index.label' => 'Indexation',
'fabianmichael.meta.robots_index.help' => 'Les moteurs de recherche sont autorisés à indexer cette page.',
'fabianmichael.meta.robots_follow.label' => 'Suivre les liens',
'fabianmichael.meta.robots_follow.help' => 'Les moteurs de recherche pourront suivre les liens sur cette page.',
'fabianmichael.meta.robots_archive.label' => 'Archiver',
'fabianmichael.meta.robots_archive.help' => 'Les moteurs de recherche pourront mettre cette page en cache.',
'fabianmichael.meta.robots_imageindex.label' => 'Indexer les images',
'fabianmichael.meta.robots_imageindex.help' => 'Les moteurs de recherche pourront associer cette page à des résultate de recherche d\'images.',
'fabianmichael.meta.robots_snippet.label' => 'Aperçus',
'fabianmichael.meta.robots_snippet.help' => 'Les moteurs de recherche pourront afficher un aperçu de la page parmi les résultats de recherche.',
'fabianmichael.meta.global_robots.headline' => 'Paramètres des moteurs de recherche',
'fabianmichael.meta.global_robots.help' => 'Des informations détaillées sur comment les moteurs de recherche doivent traiter les pages de ce site. Les pages peuvent avoir leurs propres paramètres pour remplacer ceux-ci.',
'fabianmichael.meta.global_robots_index.label' => 'Indexation',
'fabianmichael.meta.global_robots_index.help' => 'Les moteurs de recherche sont autorisés à indexer cette page.',
'fabianmichael.meta.global_robots_follow.label' => 'Suivre les liens',
'fabianmichael.meta.global_robots_follow.help' => 'Les moteurs de recherche pourront suivre les liens sur cette page.',
'fabianmichael.meta.global_robots_archive.label' => 'Archiver',
'fabianmichael.meta.global_robots_archive.help' => 'Les moteurs de recherche pourront mettre cette page en cache.',
'fabianmichael.meta.global_robots_imageindex.label' => 'Indexer les images',
'fabianmichael.meta.global_robots_imageindex.help' => 'Les moteurs de recherche pourront associer cette page à des résultate de recherche d\'images.',
'fabianmichael.meta.global_robots_snippet.label' => 'Aperçus',
'fabianmichael.meta.global_robots_snippet.help' => 'Les moteurs de recherche pourront afficher un aperçu de la page parmi les résultats de recherche.',
'fabianmichael.meta.description.label' => 'Description',
'fabianmichael.meta.description.help' => 'Une brève description de la page qui sera affichée juste en dessous du titre de la page par les moteurs de recherche.',
'fabianmichael.meta.global_description.help' => 'The global description will be used as fallback for all pages, that dont have a dedicated description.',
'fabianmichael.meta.global_description.help' => 'Les description globale qui sera utilisée quand une page n\'a aucune description dédiée.',
'fabianmichael.meta.canonical_url.label' => 'URL Canonique',
'fabianmichael.meta.canonical_url.help' => 'L\'URL canonique de la page. Équivaut par défaut à l\'URL de la page quand ce champ est vide.',
'fabianmichael.meta.global_default_value.label' => 'Global ({ state })',
'fabianmichael.meta.config_default_value.label' => 'Par défaut ({ state })',
'fabianmichael.meta.state.on' => 'activé',
'fabianmichael.meta.state.off' => 'désactivé',
'fabianmichael.meta.state.unset' => 'Non renseigné',
'fabianmichael.meta.og.headline' => 'Partage sur les médias sociaux (OpenGraph)',
'fabianmichael.meta.og.help' => 'Les métadonnées [Open Graph](https://ogp.me/) sont utilisées par les réseaux sociaux (e.g. Facebook, Twitter) et la plupart des applications de messagerie (e.g. Signal, Telegram, iMessage).',
'fabianmichael.meta.og_site_name.label' => 'Nom partagé du site',
'fabianmichael.meta.og_site_name.help' => 'Le nom qui sera affiché sur tous les médias sociaux à des fins de partage. Si vide, le titre du site sera utilisé.',
'fabianmichael.meta.global_og_image.label' => 'L\'image partagée par défaut (globale)',
'fabianmichael.meta.global_og_image.help' => 'Une image qui illustre vos pages sur les médias sociaux quand un lien est partagé. Elle sera automatiquement recadrée pour respecter les standards. Cette image est utilisée pour tout contenu n\'ayant pas d\'image dédiée.<br><br>**Dimensions recommandées:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Formats:** JPEG, PNG, GIF, WebP, AVIF',
'fabianmichael.meta.og_image.label' => 'Image pour les partages',
'fabianmichael.meta.og_image.help' => 'Une image qui illustre vos pages sur les médias sociaux quand un lien est partagé. Elle sera automatiquement recadrée pour respecter les standards. Si vide, l\'image par défaut sera utilisée.<br><br>**Dimensions recommandées:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Formats:** JPEG, PNG, GIF, WebP, AVIF {< site.metaPanelWarning("no_og_image_fallback") >}',
'fabianmichael.meta.og_title.label' => 'Titre pour les partages',
'fabianmichael.meta.og_title.help' => 'Le titre de votre page telle qu\'elle devra apparaitre quand elle est partagée. Si vide, **Titre (Forcé)** ou le titre de la page sera utilisé.',
'fabianmichael.meta.og_description.label' => 'Description pour les partages',
'fabianmichael.meta.og_description.help' => 'Une description de votre sujet en une ou deux phrases. Si vide, la description de la page ou du site sera utilisée.',
'fabianmichael.meta.image.empty' => 'Aucune image n\'est sélectionnée.',
'fabianmichael.meta.files.headline' => 'Fichiers',
'fabianmichael.meta.sitemap.priority.label' => 'Priorités du sitemap',
'fabianmichael.meta.sitemap.priority.help' => 'Priorité relative comparé aux autres pages du site.',
'fabianmichael.meta.sitemap.global_priority.help' => 'Priorité par défaut pour toutes les pages du site. Le paramétrage d\'une priorité indique aux moteurs de recherche l\'importance relative de vos pages par rapport aux autres.',
'fabianmichael.meta.sitemap.changefreq.label' => 'Fréquence de modification',
'fabianmichael.meta.sitemap.changefreq.help' => 'Indique aux moteurs de recherche à quelle fréquence le contenu associé change.',
'fabianmichael.meta.sitemap.changefreq.always' => 'Toujours',
'fabianmichael.meta.sitemap.changefreq.hourly' => 'Horaire',
'fabianmichael.meta.sitemap.changefreq.daily' => 'Quotidiennement',
'fabianmichael.meta.sitemap.changefreq.weekly' => 'Hebdomadaire',
'fabianmichael.meta.sitemap.changefreq.monthly' => 'Mensuel',
'fabianmichael.meta.sitemap.changefreq.yearly' => 'Annuel',
'fabianmichael.meta.sitemap.changefreq.never' => 'Jamais',
'fabianmichael.meta.twitter.headline' => 'Twitter',
'fabianmichael.meta.twitter.site.label' => 'Nom d\'utilisateur Twitter associé au site',
'fabianmichael.meta.twitter.creator.label' => 'Nom d\'utilisateur Twitter associé au contenu de cette page.',
'fabianmichael.meta.no_og_image_fallback' => 'Aucune image globale de repli n\'est définie. Merci d\'aller aux <a href="{ link }">paramètres globaux des méta-données</a> pour en configurer une.',
'fabianmichael.meta.schema.person_privacy_notice.label' => 'Avis de confidentialité',
'fabianmichael.meta.schema.person_privacy_notice.text' => 'By selecting a user, you will expose personal information such as the email address and profile image to search engines, other crawlers and everyone who reads the source code of your website.',
'fabianmichael.meta.schema.person_privacy_notice.text' => 'En sélectionnant un utilisateur, vous exposez certaines données personnelles telles que son adresse email et son image de profil aux moteurs de recherche, aux autres robots et à toute personne consultant le code source du site internet.',
'fabianmichael.meta.sharing_preview.headline' => 'Aperçu des données partagées',
'fabianmichael.meta.description_missing' => '[Share Description and fallback Description Missing]',
'fabianmichael.meta.description_missing' => '[Aucune description, ni de description de repli]',
'fabianmichael.meta.source.og_image' => 'Source: Image pour les partages',
'fabianmichael.meta.source.metadata' => 'Source: Image de la page',
'fabianmichael.meta.source.site' => 'Source: Image globale du site',
'fabianmichael.meta.og_image.missing' => 'Image Manquante',
'fabianmichael.meta.schema.headline' => 'Données structurées',
'fabianmichael.meta.schema.help' => 'Ces données sont basées sur le standard établi par [Schema.org](https://schema.org) et peut être consulté par les moteurs de recherche tel que [Google](https://google.com) afin de mieux comprendre votre organisation ou votre personne.',
'fabianmichael.meta.schema.website_owner.label' => 'Propriétaire du site',
'fabianmichael.meta.schema.website_owner.help' => 'Sélectionnez si ce site représente une organisation ou une personne individuelle.',
'fabianmichael.meta.schema.org_name.label' => 'Nom de l\'organisation',
'fabianmichael.meta.schema.org_logo.label' => 'Logo de l\'organisation',
'fabianmichael.meta.schema.meta_person.label' => 'Personne',
'fabianmichael.meta.schema.meta_person.empty' => 'Aucune personne sélectionnée',
'fabianmichael.meta.schema.meta_person.help' => 'Sélectionnez un utilisateur qui représente ce site.',
'fabianmichael.meta.status.label' => 'Statut',
'fabianmichael.meta.search_engines.visibility.visible' => 'Visible',
'fabianmichael.meta.search_engines.visibility.hidden' => 'Caché',
'fabianmichael.meta.search_engines.visibility.label' => 'Visibilité pour les moteurs de recherche',
'fabianmichael.meta.search_engines.visibility.yes' => 'This page is indexed by search engines and may appear in search results',
'fabianmichael.meta.search_engines.visibility.yes' => 'Cette page est indexable par les moteurs de recherche et peut apparaitre dans les résultats de recherche.',
'fabianmichael.meta.search_engines.visibility.no' => 'Cette page n\'est pas autorisée à être indexée par les moteurs de recherche. Elle n\'apparaîtra pas dans les résultats de recherche.',
];

View file

@ -0,0 +1,111 @@
<?php
return [
'fabianmichael.meta.tab.label' => 'Metadata (SEO)',
'fabianmichael.meta.page_title.placeholder' => 'Sidtitel',
'fabianmichael.meta.title_preview.label' => 'Titelförhandsgranskning',
'fabianmichael.meta.global_settings.headline' => 'Globala inställningar',
'fabianmichael.meta.global_general.headline' => 'Allmänna inställningar',
'fabianmichael.meta.general.headline' => 'Grundläggande meta-information',
'fabianmichael.meta.title.label' => 'Titel (Prioriterad)',
'fabianmichael.meta.title.help' => 'Sidans titel som den ska visas i sökmotorer. Kommer att använda Kirbys sidtitel som standard när detta fält är tomt.',
'fabianmichael.meta.title_separator.label' => 'Titelseparator',
'fabianmichael.meta.title_separator.help' => 'Separator som ska visas mellan sid- och webbplatsens titel.',
'fabianmichael.meta.robots.headline' => 'Sökmotorer',
'fabianmichael.meta.robots.help' => 'Detaljerade instruktioner om hur sökmotorer ska hantera denna sida.',
'fabianmichael.meta.robots_index.label' => 'Indexering',
'fabianmichael.meta.robots_index.help' => 'Sökmotorer får indexera denna sida.',
'fabianmichael.meta.robots_follow.label' => 'Följ länkar',
'fabianmichael.meta.robots_follow.help' => 'Sökmotorer kommer att följa länkar på denna sida.',
'fabianmichael.meta.robots_archive.label' => 'Arkivering',
'fabianmichael.meta.robots_archive.help' => 'Sökmotorer kommer att cachelagra denna sida.',
'fabianmichael.meta.robots_imageindex.label' => 'Bildindexering',
'fabianmichael.meta.robots_imageindex.help' => 'Sökmotorer kommer att associera denna sida med bildsökresultat.',
'fabianmichael.meta.robots_snippet.label' => 'Snippets',
'fabianmichael.meta.robots_snippet.help' => 'Sökmotorer kommer att visa beskrivning för denna sida.',
'fabianmichael.meta.global_robots.headline' => 'Inställningar för sökmotorer',
'fabianmichael.meta.global_robots.help' => 'Detaljerade instruktioner om hur sökmotorer ska hantera sidor på denna webbplats som standard. Sidor kan ha sina individuella inställningar som åsidosätter dessa standarder.',
'fabianmichael.meta.global_robots_index.label' => 'Indexering',
'fabianmichael.meta.global_robots_index.help' => 'Sökmotorer får indexera denna webbplats.',
'fabianmichael.meta.global_robots_follow.label' => 'Följ länkar',
'fabianmichael.meta.global_robots_follow.help' => 'Sökmotorer kommer att följa länkar på denna webbplats.',
'fabianmichael.meta.global_robots_archive.label' => 'Arkivering',
'fabianmichael.meta.global_robots_archive.help' => 'Sökmotorer kommer att cachelagra sidor på denna webbplats.',
'fabianmichael.meta.global_robots_imageindex.label' => 'Bildindexering',
'fabianmichael.meta.global_robots_imageindex.help' => 'Sökmotorer kommer att associera sidor med bildsökresultat.',
'fabianmichael.meta.global_robots_snippet.label' => 'Snippets',
'fabianmichael.meta.global_robots_snippet.help' => 'Sökmotorer kommer att visa beskrivningar för sidor.',
'fabianmichael.meta.description.label' => 'Beskrivning',
'fabianmichael.meta.description.help' => 'En kort beskrivning av sidan som kommer att visas under sidtiteln av sökmotorer.',
'fabianmichael.meta.global_description.help' => 'Den globala beskrivningen kommer att användas som fallback för alla sidor som inte har en dedikerad beskrivning.',
'fabianmichael.meta.canonical_url.label' => 'Kanonisk URL',
'fabianmichael.meta.canonical_url.help' => 'Sidans kanoniska URL. Kommer att använda sidans URL som standard när detta fält är tomt.',
'fabianmichael.meta.global_default_value.label' => 'Webbplats ({ state })',
'fabianmichael.meta.config_default_value.label' => 'Konfiguration ({ state })',
'fabianmichael.meta.state.on' => 'på',
'fabianmichael.meta.state.off' => 'av',
'fabianmichael.meta.state.unset' => 'inte satt',
'fabianmichael.meta.og.headline' => 'Dela på sociala medier',
'fabianmichael.meta.og.help' => '[Open Graph](https://ogp.me/) metadata används av sociala nätverk (t.ex. Facebook, Twitter) och de flesta meddelandeappar (t.ex. Signal, Telegram, iMessage).',
'fabianmichael.meta.og_site_name.label' => 'Dela webbplatsnamn',
'fabianmichael.meta.og_site_name.help' => 'Namnet som ska visas för hela webbplatsen vid delning på sociala medier. Kommer att använda webbplatsens titel som fallback.',
'fabianmichael.meta.global_og_image.label' => 'Standard delningsbild',
'fabianmichael.meta.global_og_image.help' => 'En bild som ska representera dina delade länkar på sociala medier och appar. Kommer att beskäras automatiskt. Denna globala bild används som fallback för sidor som inte har en dedikerad bild.<br><br>**Rekommenderad storlek:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Format:** JPEG, PNG, GIF, WebP, AVIF',
'fabianmichael.meta.og_image.label' => 'Delbild',
'fabianmichael.meta.og_image.help' => 'En bild som ska representera dina delade länkar på sociala medier och appar. Kommer att beskäras automatiskt. Kommer att använda den globalt definierade fallbackbilden som fallback.<br><br>**Rekommenderad storlek:** 1200&thinsp;&times;&thinsp;630&nbsp;px<br>**Format:** JPEG, PNG, GIF, WebP, AVIF {< site.metaPanelWarning("no_og_image_fallback") >}',
'fabianmichael.meta.og_title.label' => 'Del-titel (överstyrning)',
'fabianmichael.meta.og_title.help' => 'Titeln på din sida som den ska visas vid delning. Kommer att använda **Titel (överstyrning)** och sidtitel som fallback.',
'fabianmichael.meta.og_description.label' => 'Del-beskrivning',
'fabianmichael.meta.og_description.help' => 'En till två meningars beskrivning av objektet. Kommer att använda sidbeskrivning och webbplatsbeskrivning som fallbacks.',
'fabianmichael.meta.image.empty' => 'Ingen bild vald ännu',
'fabianmichael.meta.files.headline' => 'Filer',
'fabianmichael.meta.sitemap.priority.label' => 'Prioritet i sitemap',
'fabianmichael.meta.sitemap.priority.help' => 'Relativ prioritet jämfört med andra sidor på din webbplats.',
'fabianmichael.meta.sitemap.global_priority.help' => 'Standardprioritet för alla sidor på denna webbplats. Att ange en prioritet ger en ledtråd till sökmotorer om den relativa vikten av dina sidor i jämförelse med varandra.',
'fabianmichael.meta.sitemap.changefreq.label' => 'Ändringsfrekvens',
'fabianmichael.meta.sitemap.changefreq.help' => 'Berättar för sökmotorer hur ofta innehållet ändras.',
'fabianmichael.meta.sitemap.changefreq.always' => 'Alltid',
'fabianmichael.meta.sitemap.changefreq.hourly' => 'Varje timme',
'fabianmichael.meta.sitemap.changefreq.daily' => 'Dagligen',
'fabianmichael.meta.sitemap.changefreq.weekly' => 'Veckovis',
'fabianmichael.meta.sitemap.changefreq.monthly' => 'Månadsvis',
'fabianmichael.meta.sitemap.changefreq.yearly' => 'Årligen',
'fabianmichael.meta.sitemap.changefreq.never' => 'Aldrig',
'fabianmichael.meta.twitter.headline' => 'Twitter',
'fabianmichael.meta.twitter.site.label' => 'Twitter-användarnamn för webbplatsen',
'fabianmichael.meta.twitter.creator.label' => 'Twitter-användarnamn för innehållsskapare',
'fabianmichael.meta.no_og_image_fallback' => 'Ingen global reservbild definierad. Gå till <a href="{ link }">globala metadatinställningar</a> och ladda upp en.',
'fabianmichael.meta.schema.person_privacy_notice.label' => 'Integritetsmeddelande',
'fabianmichael.meta.schema.person_privacy_notice.text' => 'Genom att välja en användare kommer du att exponera personlig information som e-postadress och profilbild för sökmotorer, andra webbskrapor och alla som läser källkoden till din webbplats.',
'fabianmichael.meta.sharing_preview.headline' => 'Delningsförhandsvisning',
'fabianmichael.meta.description_missing' => '[Delbeskrivning och fallback-beskrivning saknas]',
'fabianmichael.meta.source.og_image' => 'Källa: Delbild',
'fabianmichael.meta.source.metadata' => 'Källa: Sidminiatyr',
'fabianmichael.meta.source.site' => 'Källa: Fallback-miniatyr',
'fabianmichael.meta.og_image.missing' => 'Bild saknas',
'fabianmichael.meta.schema.headline' => 'Strukturerad data',
'fabianmichael.meta.schema.help' => 'Denna data är baserad på standarden [Schema.org](https://schema.org) och kan plockas upp av sökmotorer som [Googles](https://google.com) kunskapsgraf för bättre förståelse av din organisation eller person.',
'fabianmichael.meta.schema.website_owner.label' => 'Webbplatsägare',
'fabianmichael.meta.schema.website_owner.help' => 'Välj om din webbplats representerar en organisation eller individuell person.',
'fabianmichael.meta.schema.org_name.label' => 'Organisationsnamn',
'fabianmichael.meta.schema.org_logo.label' => 'Organisationslogo',
'fabianmichael.meta.schema.meta_person.label' => 'Person',
'fabianmichael.meta.schema.meta_person.empty' => 'Ingen användare vald ännu',
'fabianmichael.meta.schema.meta_person.help' => 'Välj en användare som representerar denna webbplats.',
'fabianmichael.meta.status.label' => 'Status',
'fabianmichael.meta.search_engines.visibility.visible' => 'Synlig',
'fabianmichael.meta.search_engines.visibility.hidden' => 'Dold',
'fabianmichael.meta.search_engines.visibility.label' => 'Sökmotorvisibilitet',
'fabianmichael.meta.search_engines.visibility.yes' => 'Denna sida är indexerad av sökmotorer och kan visas i sökresultat',
'fabianmichael.meta.search_engines.visibility.no' => 'Denna sida är dold från sökresultat',
];

View file

@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="format-detection" content="telephone=no">
<title><?= $site->title()->esc() ?> | <?= $page->title()->esc() ?></title>
<?php snippet('meta') ?>
<?php foreach ($kirby->languages() as $language): ?>
<link rel="alternate" hreflang="<?= $language->code() ?>" href="<?= $page->url($language->code()) ?>">

View file

@ -19,4 +19,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit0bf5c8a9cfa251a218fc581ac888fe35::getLoader();
return ComposerAutoloaderInit6bd7ca31919a06523740c63d3abf0d28::getLoader();

0
kirby/vendor/bin/yaml-lint → vendor/bin/yaml-lint vendored Normal file → Executable file
View file

Some files were not shown because too many files have changed in this diff Show more