Skip to content

Commit

Permalink
feat!: urlParser for resolvePermalinks
Browse files Browse the repository at this point in the history
  • Loading branch information
johannschopplich committed Nov 21, 2023
1 parent d4cd07b commit d014e11
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 47 deletions.
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,21 +271,38 @@ A middleware checks if a `Authentication` header is set, which is not the case i

### `resolvePermalinks()`

This field method resolves page and file permalinks to their respective URLs. It is primarily intended for usage with KQL queries, because the value of `writer` fields contain permalink URLs like `/@/page/nDvVIAwDBph4uOpm`. But the method works with any field that contains permalinks in `href` attributes.
This field method resolves page and file permalinks to their respective URLs. It is primarily intended for usage with KQL queries, because the value of `writer` fields contain permalink URLs like `/@/page/nDvVIAwDBph4uOpm`. But the method works with any field values that contains permalinks in `href` or `src` attributes.

In multilanguage setups, you may want to remove a language prefix like `/de` from the URL. You can do so by defining a custom path parser in your `config.php`:
For headless usage, you may want to remove the origin from the URL and just return the path. You can do so by defining a custom URL parser in your `config.php`:

```php
# /site/config/config.php
return [
'permalinksResolver' => [
// Strip the language code prefix from the URL for German
'pathParser' => function (string $path, \Kirby\Cms\App $kirby) {
// Strip the origin from the URL
'urlParser' => function (string $url, \Kirby\Cms\App $kirby) {
$path = parse_url($url, PHP_URL_PATH);
return $path;
}
]
];
```

Or in multilanguage setups, you may want to remove a language prefix like `/de` from the URL:

```php
# /site/config/config.php
return [
'permalinksResolver' => [
// Strip the language code prefix from German URLs
'urlParser' => function (string $url, \Kirby\Cms\App $kirby) {
$path = parse_url($url, PHP_URL_PATH);
if (str_starts_with($path, '/de')) {
return substr($path, 3);
}
return '';
return $path;
}
]
];
Expand Down
24 changes: 12 additions & 12 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 37 additions & 30 deletions src/extensions/fieldMethods.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<?php

$filesFieldResolver = function (\Kirby\Cms\Block $block) {
use Kirby\Cms\Block;
use Kirby\Content\Field;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Dom;
use Kirby\Uuid\Uuid;

$filesFieldResolver = function (Block $block) {
$kirby = $block->kirby();
$blocks = $kirby->option('blocksResolver.files', ['image' => 'image']);

Expand Down Expand Up @@ -48,7 +54,7 @@
return $block;
};

$pagesFieldResolver = function (\Kirby\Cms\Block $block) {
$pagesFieldResolver = function (Block $block) {
$kirby = $block->kirby();
$blocks = $kirby->option('blocksResolver.pages', []);

Expand Down Expand Up @@ -94,7 +100,7 @@
};

// Support any field type
$customFieldResolver = function (\Kirby\Cms\Block $block) {
$customFieldResolver = function (Block $block) {
$kirby = $block->kirby();
$resolvers = $kirby->option('blocksResolver.resolvers', []);

Expand All @@ -118,14 +124,13 @@
return $block;
};

$nestedBlocksFieldResolver = function (\Kirby\Cms\Block $block) use ($filesFieldResolver) {
/** @var \Kirby\Cms\Block $block */
$nestedBlocksFieldResolver = function (Block $block) use ($filesFieldResolver) {
/** @var Block $block */
$kirby = $block->kirby();
$nestedBlocks = $kirby->option('blocksResolver.nested', ['prose']);
$blocksKeys = array_intersect($block->content()->keys(), $nestedBlocks);

foreach ($blocksKeys as $key) {
/** @var \Kirby\Content\Field $ktField */
$field = $block->content()->get($key);

$block->content()->update([
Expand All @@ -142,31 +147,33 @@
*
* @kql-allowed
*/
'resolvePermalinks' => function (\Kirby\Content\Field $field) {
'resolvePermalinks' => function (Field $field) {
$kirby = $field->parent()->kirby();
$pathParser = $kirby->option('permalinksResolver.pathParser', fn (string $path) => $path);

if (!is_string($field->value)) {
return $field;
}

$field->value = preg_replace_callback(
'!href="\/@\/(page|file)\/([^"]+)"!',
function ($matches) use ($kirby, $pathParser) {
$type = $matches[1]; // Either `page` or `file`
$id = $matches[2]; // The UUID

// Resolve the UUID to the actual model URL
if ($model = \Kirby\Uuid\Uuid::for($type . '://' . $id)?->model()) {
$parsedUrl = parse_url($model->url());
return 'href="' . $pathParser($parsedUrl['path'] ?? '/', $kirby) . '"';
$urlParser = $kirby->option('permalinksResolver.urlParser', fn (string $url, \Kirby\Cms\App $kirby) => $url);

if ($field->isNotEmpty()) {
$dom = new Dom($field->value);
$attributes = ['href', 'src'];
$elements = $dom->query('//*[' . implode(' | ', A::map($attributes, fn ($attribute) => '@' . $attribute)) . ']');

foreach ($elements as $element) {
foreach ($attributes as $attribute) {
if ($element->hasAttribute($attribute) && $url = $element->getAttribute($attribute)) {
try {
if ($uuid = Uuid::for($url)) {
$url = $uuid->model()?->url();
$parsedUrl = $url ? $urlParser($url, $kirby) : null;
$element->setAttribute($attribute, $parsedUrl);
}
} catch (InvalidArgumentException) {
// Ignore anything else than permalinks
}
}
}
}

// If not resolvable, return the original match
return $matches[0];
},
$field->value
);
$field->value = $dom->toString();
}

return $field;
},
Expand All @@ -176,7 +183,7 @@ function ($matches) use ($kirby, $pathParser) {
*
* @kql-allowed
*/
'toResolvedBlocks' => function (\Kirby\Content\Field $field) use ($pagesFieldResolver, $filesFieldResolver, $customFieldResolver, $nestedBlocksFieldResolver) {
'toResolvedBlocks' => function (Field $field) use ($pagesFieldResolver, $filesFieldResolver, $customFieldResolver, $nestedBlocksFieldResolver) {
return $field
->toBlocks()
->map($nestedBlocksFieldResolver)
Expand All @@ -190,7 +197,7 @@ function ($matches) use ($kirby, $pathParser) {
*
* @kql-allowed
*/
'toResolvedLayouts' => function (\Kirby\Content\Field $field) use ($filesFieldResolver, $pagesFieldResolver, $customFieldResolver) {
'toResolvedLayouts' => function (Field $field) use ($filesFieldResolver, $pagesFieldResolver, $customFieldResolver) {
return $field
->toLayouts()
->map(function (\Kirby\Cms\Layout $layout) use ($filesFieldResolver, $pagesFieldResolver, $customFieldResolver) {
Expand Down

0 comments on commit d014e11

Please sign in to comment.