Headless

Usage

Configure the Kirby Headless plugin to your needs.

Authentication

The Kirby Headless plugin exposes your content to the public by default. To secure your API, you can enable bearer token authentication for the KQL and custom API endpoints. This is especially useful for KQL requests, as Kirby's default KQL endpoint only supports basic authentication.

To enable bearer token authentication, set the headless.token global option in your config.php to a secret string:

config.php
return [
    'headless' => [
        'token' => 'test'
    ]
];

You will then need to include the HTTP header Authorization: Bearer {token} with every request.

The internal /api/kql endpoint will always enforce bearer authentication, unless you explicitly disable it by setting the kql.auth option to false.

Cross Origin Resource Sharing (CORS)

CORS issues are a common problem when fetching data from a different domain. To allow cross-origin requests, Kirby Headless responds with the appropriate CORS headers for preflight requests. You can customize the CORS configuration in your config.php:

config.php
return [
    'headless' => [
        // Default CORS configuration
        'cors' => [
            'allowOrigin' => '*',
            'allowMethods' => 'GET, POST, OPTIONS',
            'allowHeaders' => 'Accept, Content-Type, Authorization, X-Language',
            'maxAge' => '86400',
        ]
    ]
];

Kirby Query Language (KQL)

It is common to authenticate API requests with a token, which is not possible with the default KQL endpoint (/api/query as defined by the official KQL plugin). To solve this problem, this plugin adds a new KQL endpoint under /api/kql that supports the following features:

  • Bearer token authentication
  • Query response caching
  • Multi-language support

To enable the bearer token authentication for KQL query requests to /api/kql, set the following option in your config.php:

config.php
return [
    // Default to token-based authentication
    'kql' => [
        'auth' => 'bearer'
    ]
];

Now fetch the KQL query results as you normally would, but include an `Authentication' header with the bearer token in your request:

const response = await fetch("https://example.com/api/kql", {
  method: "POST",
  body: {
    query: "site",
    select: {
      title: true,
      photography: {
        query: "page('photography').children",
        select: ["title", "url"],
      },
    },
  },
  headers: {
    Authorization: `Bearer ${process.env.KIRBY_API_TOKEN}`,
  },
});

const data = await response.json();
console.log(data);

Basic Authentication for KQL

If you prefer the default basic authentication method, you can still enable it by setting the kql.auth option to true. This will disable bearer token authentication, but still provide features like caching and multi-language support:

config.php
return [
    // Enable basic authentication for the Kirby API (required for KQL)
    'api' => [
        'basicAuth' => true
    ],

    // Default to basic authentication
    'kql' => [
        'auth' => true
    ]
];
The default KQL endpoint /api/query always continues to use basic authentication and also derives the kql.auth configuration option.

Panel Configuration

Preview URL to the Frontend

If you are running a headless CMS, the default preview links from the Kirby Panel won't make much sense because they point to the backend URL. We need to change the hostname of the generated preview URLs to the frontend URL. To do this, set the preview option in your template to a Kirby query that calls the frontendUrl page method provided by this plugin:

site/blueprints/pages/default.yml
options:
  # Or `site.frontendUrl` for the `site.yml`
  preview: "{{ page.frontendUrl }}"

Finally, set the frontendUrl option in your config.php:

config.php
return [
    'headless' => [
        'panel' => [
            'frontendUrl' => 'https://example.com'
        ]
    ]
];

If the value is empty, the preview button will be disabled altogether.

Redirect to the Panel

If your Kirby project is headless only and no visual content is served, you may want to redirect editors to the Panel when they visit the backend. You could create a default template with a redirect, but it's easier to set the redirect option in your config.php:

config.php
return [
    'headless' => [
        'panel' => [
            'redirect' => true
        ]
    ]
];

JSON Templates

When writing a Kirby template, it will be rendered as HTML by default. To opt-in to JSON templates, you can encode the template data as JSON and return it as a response. This is useful for headless setups where KQL is not sufficient or you want to control the data structure in PHP.

Kirby Headless does not interfere with Kirby's default routing. To overwrite Kirby's global routing to return JSON templates, set the globalRoutes option in your config.php:

config.php
return [
    'headless' => [
        'globalRoutes' => true
    ]
];

Template Example

Writing templates as JSON is straightforward. Here is an example of how to encode the data of an about template as JSON:

site/templates/about.php
$data = [
  'title' => $page->title()->value(),
  'layout' => $page->layout()->toLayouts()->toArray(),
  'address' => $page->address()->value(),
  'email' => $page->email()->value(),
  'phone' => $page->phone()->value(),
  'social' => $page->social()->toStructure()->toArray()
];

echo \Kirby\Data\Json::encode($data);

To fetch the JSON template data, you can use the following JavaScript example:

const response = await fetch("https://example.com/about", {
  headers: {
    Authorization: `Bearer ${process.env.KIRBY_API_TOKEN}`,
  },
});

const data = await response.json();
console.log(data);