Skip to content
XSLT for Kirby
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

XSLT for Kirby 3

We work as designers, and over the years we have fallen in love with XSLT for templating. XSLT allows you to transform XML to any other structure by applying templates and thus you can use it to generate HTML from structured data. The syntax looks like HTML and works like CSS conceptually.

This plugin enables XSLT templating in your Kirby install by generating XML for all front-end pages. You can setup custom nodes and specify included elements for each page.



This plugin requires PHP's LibXML module with the XSLT extension enabled (--with-xsl) in order to work.

Via Download

Download the latest release from, unzip all files and copy them to the plugin folder at /site/plugins/xslt.

Via Git Submodule

Add this repository as submodule to /site/plugins/xslt:

git submodule add site/plugins/xslt

Via Composer

Require this plugin using composer:

composer require hananils/xslt


By default, the plugin provides XML nodes for the $kirby, $site, $pages and $page objects. As soon as you are logged in, you can view the data of any page by appending ?data to the URL. The base output without additional setting using the Plainkit looks similar to this:

<?xml version="1.0" encoding="UTF-8"?>
    <kirby content-extension="txt" version="3.0.1">
            <index host="localhost" path="" port="8888" scheme="http">http://localhost:8888</index>
            <base host="localhost" path="" port="8888" scheme="http">http://localhost:8888</base>
            <current host="localhost" path="" port="8888" scheme="http">http://localhost:8888</current>
            <assets host="localhost" path="/assets" port="8888" scheme="http">http://localhost:8888/assets</assets>
            <api host="localhost" path="/api" port="8888" scheme="http">http://localhost:8888/api</api>
            <media host="localhost" path="/media" port="8888" scheme="http">http://localhost:8888/media</media>
            <panel host="localhost" path="/panel" port="8888" scheme="http">http://localhost:8888/panel</panel>
        <user id="dac9630a" language="de" role="admin">
            <username>Nils Hörrmann</username>
            <email alias="buero" domain="" hash="9f8e362eca81e9723d9e699a45caf841"></email>
    <page id="home" slug="home" status="unlisted" template="default" uid="home" url="http://localhost:8888">
        <page id="error" slug="error" status="unlisted" template="default" uid="error" url="http://localhost:8888/error">
            <path url="error">
                <param template="default" title="Error">error</param>
        <page id="home" slug="home" status="unlisted" template="default" uid="home" url="http://localhost:8888">
            <path url="home">
                <param template="default" title="Home">home</param>
    <site url="http://localhost:8888">
        <title>hana+nils · Büro für Gestaltung</title>

Any object defined in a controller will be added to the XML output as well, e. g.:


return function ($kirby) {
    return [
        'projects' => $kirby->collection('projects')

Known types are:

Included Elements

In order to customize the XML output, you have to create a new folder definitions inside your site folder. Similar to your blueprints, you can create definitions files for each template. The default.yml might look like this for example:

kirby: true
site: true
page: true
pages: false

The key equals the object name, let this be the default $kirby, $site, $pages or $page objects or a custom controller returning a project object. Setting an object to true will show the full content, setting an object to false will exclude its content.

The different type have different subsettings:


The kirby object can only be switched on and off by either setting it to true or false. If you are working on a multilingual install, language settings are available, too:

    <language code="de" direction="ltr" locale="de_DE.uft-8" url="http://localhost:8888/de" default="true" current="true">Deutsch</language>
    <language code="en" direction="ltr" locale="en_US.uft-8" url="http://localhost:8888/en">Englisch</language>

Site and Page

The page objects know the following subsettings:

    title: true
    path: true
    languages: true
    content: true
    files: true
    children: false
  • The title object can be switched on and off by setting true or false.
  • The path object is helpful to apply different templates base on the URL, it can be switched on and off by setting true or false.
  • The languages object is available in multilingual installs and offers link for all languages, it can be switched on and off by setting true or false.
  • The content subsetting takes and array of fields you'd like to include, e. g. content: title, description, tags.
  • The files object can be switched on and off by setting true or false. It also takes additional settings, see below.
  • The files object can be switched on and off by setting true or false. It also takes additional settings from the pages object, see below.

Additional field settings

There is one field with additional settings: the textarea field accepts format settings unformatted, markdown or kirbytext. The default is kirbytext. If you'd like to change the default, the content object needs to be changed from:

content: title, description, tags


    title: true
    description: unformatted
    tags: true

Telephone field

When using a Composer setup, you can install the optional libphonenumber library. This will add additional phone number formats to the XML output (E164, national, international and RFC3966).


The pages objects returns a collection of child pages. It takes the same settings as the page object which are applied to all children.


The files object returns a collection of files grouped by file template:

filename: true
meta: description, credits, focus
    - width: 600
      height: 400
      crop: left
    - width: 1200
      crop: fields.focus
    - width: 1800
  • The filename can be switched on and off by setting true or false.
  • The meta object equals the content object of a page, see above.
  • The thumbs object lets you setup image thumbnails. It takes a list of thumbs with optional settings for width, height and crop position. If your crop position is stored in a field, you can reference it using the syntax fields.fieldname.

Extending Included Elements

You can create subfolders for files and pages, /site/definitions/files and /site/definitions/pages to create subsets for settings you'd like to reuse across defintions files. This works like in blueprints.

Extending the default definitions:

extends: default

Extending file definitions


filename: true
meta: description, credits, focus
    - width: 600
      height: 400
      crop: left
    - width: 1200
      crop: fields.focus
    - width: 1800


    title: true
    content: title, description, url, date, tags
            extends: files/image

Extending page definitions


title: true
path: true


    extends: default

Helper Objects

The plugin bundles two helper objects to be used inside your controllers:


return function ($kirby) {
    return [
        'datetime' => $kirby->collection('datetime'),
        'assets' => $kirby->collection('assets')

Date and Time

This object returns current date and time information as well as localized month and weekday names:

    <today day="14" iso="2019-02-14T20:24:38+00:00" month="2" offset="+0000" time="20:24" timestamp="1550175878" weekday="4" year="2019">2019-02-14</today>
    <language id="en" locale="en_ca">
            <month abbr="Jan" id="1">January</month>
            <month abbr="Feb" id="2">February</month>
            <month abbr="Mar" id="3">March</month>
            <month abbr="Apr" id="4">April</month>
            <month abbr="May" id="5">May</month>
            <month abbr="Jun" id="6">June</month>
            <month abbr="Jul" id="7">July</month>
            <month abbr="Aug" id="8">August</month>
            <month abbr="Sep" id="9">September</month>
            <month abbr="Oct" id="10">October</month>
            <month abbr="Nov" id="11">November</month>
            <month abbr="Dec" id="12">December</month>
            <weekday abbr="Sun" id="1">Sunday</weekday>
            <weekday abbr="Mon" id="2">Monday</weekday>
            <weekday abbr="Tue" id="3">Tuesday</weekday>
            <weekday abbr="Wed" id="4">Wednesday</weekday>
            <weekday abbr="Thu" id="5">Thursday</weekday>
            <weekday abbr="Fri" id="6">Friday</weekday>
            <weekday abbr="Sat" id="7">Saturday</weekday>

The used locale can be set in the config:


return [
    'locale' => 'en_CA.utf-8'

If you are working on a multilingual site, all languages you've set up will be available.


This object return information about all files and folders inside the /asset folder:

        <file extension="png" mime="image/png" modified="1544107969">apple-touch-icon.png</file>
        <file extension="js" mime="text/plain" modified="1549887572">app.js</file>
        <file extension="css" mime="text/plain" modified="1544531895">app.globals.css</file>
        <file extension="css" mime="text/plain" modified="1549887572">app.layouts.css</file>

This information can be used to automatically generate links for scripts and styles:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"

<xsl:template match="data">
            <xsl:apply-templates select="assets/styles/file[@extension = 'css']" />

<xsl:template match="assets/styles/file[@extension = 'css']">
    <link rel="stylesheet" type="text/css" href="{$assets}/{@modified}/{name(..)}/{.}" />


It's also possible to use the modified attribute to create timestamped links:

# in your .htaccess
RewriteRule ^assets/([0-9]+)/(.*)$ ./assets/$2 [L,NC]


Templates are defined in the default templates and snippets folders. If you are using the Kirby Starterkit or Plainkit, please remove the default PHP templates and add a new default.xsl file. This works well as a starting point:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"

<xsl:output method="html"
    doctype-system="about:legacy-compat" />

<xsl:template match="data">
        <xsl:value-of select="page/title" />
        <xsl:value-of select="page/title" />


Template naming conventions follow the default Kirby scheme, see


If you use doctype-system="about:legacy-compat" as in the example above, the plugin will automatically shorten the default doctype output <!DOCTYPE html SYSTEM "about:legacy-compat"> to <!DOCTYPE html>.


The plugin is work in progress. We are extending it based on our own needs:

  • Field support is limited to the core fields and a few additional fields we use ourselves.

Contributions are always welcome.

You can’t perform that action at this time.