Headless

Field Methods

Kirby Headless offers field methods to resolve data in blocks and layouts.

toResolvedBlocks()

The toResolvedBlocks() method is a wrapper around Kirby's toBlocks() method. It resolves fields in blocks to the desired output by running them through resolver functions.

For example, the toBlocks() method returns UUIDs for the files and pages fields. To leave these UUIDs as they are would require you to resolve them in your frontend application. Instead, you can use the toResolvedBlocks() method to resolve these UUIDs into file and page objects on the server. This way, you can access the properties of these objects directly in your frontend.

When using toBlocks(), a single block as part of the blocks JSON response might look like this:

{
  "content": {
    "image": ["file://BYXR0pvumEbfTknP"],
    "alt": "Staring at stars"
  },
  "id": "a1c0f653-2e36-4b07-a7fa-d22ef27dd114",
  "isHidden": false,
  "type": "image"
}

Instead, when using toResolvedBlocks(), the same block would look as follows. Note that the image field is now resolved to a file object:

{
  "content": {
    "alt": "Staring at stars",
    "image": [
      {
        "url": "http://cacao-kit-backend.test/media/pages/notes/exploring-the-universe/a6c422e141-1714659501/tent-in-the-woods.jpg",
        "width": 1024,
        "height": 683
      }
    ]
  },
  "id": "a1c0f653-2e36-4b07-a7fa-d22ef27dd114",
  "isHidden": false,
  "type": "image"
}

You can define which fields of which blocks need resolving in your config.php. To simplify files and pages resolving, Kirby Headless comes with default resolvers for these fields. You can also define custom resolvers for specific fields in specific blocks.

For a production-ready boilerplate, you can use the 🍫 Cacao Kit frontend which uses this field method.

Files and Pages Resolver

In most cases, you want to resolve the files and pages fields in your blocks. To do so, you can define which fields of which blocks should be resolved in your config.php:

config.php
return [
    'blocksResolver' => [
        // Define which fields of which blocks should be resolved
        'files' => [
            // Resolve the `image` field in the `intro` block as a file
            'intro' => ['image']
        ],
        'pages' => [
            // Resolve the `link` field in the `note` block as a page
            'note' => ['link']
        ]
    ]
];

Now, all files and pages fields in the intro and note blocks will be resolved to file and page objects, respectively.

You can customize the resolver output by defining a custom resolver (overriding the default resolvers) for the files and pages fields in your config.php. Both resolver options accept a closure that takes the File or Page model as its argument and returns an array of properties, just like the default resolver.

For reference, the default values for the files and pages resolvers are:

config.php
return [
    'blocksResolver' => [
        'defaultResolvers' => [
            'files' => fn (\Kirby\Cms\File $image) => [
              'url' => $image->url(),
              'width' => $image->width(),
              'height' => $image->height(),
              'srcset' => $image->srcset(),
              'alt' => $image->alt()->value()
            ],
            'pages' => fn (\Kirby\Cms\Page $page) => [
                'uri' => $page->uri(),
                'title' => $page->title()->value()
            ]
        ]
    ]
];

Custom Resolvers

Default resolvers are probably not enough for your use case. If you need a custom resolver for links, structures, or any other field in a particular block, you can use the blocksResolver.resolvers option. It takes an array of resolvers, where the key is {blockName}:{fieldName} and the value is a closure that takes the field and block as its arguments and returns an array of properties.

You have complete control over the output of the resolved fields. For example, you can resolve the link field of the intro block to a custom output:

config.php
use Kirby\Cms\Block;
use Kirby\Content\Field;

return [
    'blocksResolver' => [
        'resolvers' => [
            // Resolve the field `link` of the block `intro` to a custom output
            'intro:link' => fn (Field $field, Block $block) => [
                'value' => $field->value(),
                'uri' => $field->toPage()?->uri()
            ],
            // Resolve the KirbyText of the field `text` of the `note` block
            'note:text' => function (Field $field, Block $block) {
                return $field->kirbytext()->value()
            }
        ]
    ]
];

Replace Field Values

By default, resolved fields will replace the source field values in the given block. If you want to keep the source field values and store the resolved content in a separate key, you can set the resolvedKey option to a custom key:

config.php
return [
    'blocksResolver' => [
        'resolvedKey' => 'resolved'
    ]
];

With this configuration, all resolved fields will be stored in a key named resolved, leaving the original field values untouched. A resolved block might look like this:

{
  "content": {
    "alt": "Staring at stars",
    "image": ["file://BYXR0pvumEbfTknP"],
    "resolved": {
      "image": {
        "url": "http://cacao-kit-backend.test/media/pages/notes/exploring-the-universe/a6c422e141-1714659501/tent-in-the-woods.jpg",
        "width": 1024,
        "height": 683
      }
    }
  },
  "id": "a1c0f653-2e36-4b07-a7fa-d22ef27dd114",
  "isHidden": false,
  "type": "image"
}
Acts the same as Kirby's built-in permalinksToUrls() method, but supports a custom URL parser.

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

For headless usage, you may want to remove the origin from the URL and just return the path. You can do this by defining a custom URL parser in your config.php:

config.php
return [
    'permalinksResolver' => [
        // 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 multi-language setups, you may want to remove a language prefix like /de from the URL:

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 $path;
        }
    ]
];

toResolvedLayouts()

The toResolvedLayouts() method is a wrapper around Kirby's toLayouts() method. Under the hood, it uses the toResolvedBlocks() method to resolve fields in blocks. You can use the same files, pages, and custom resolvers as with the toResolvedBlocks() method.