Converting frontmatter from 'standard' YAML to Kirby YAML

I have a website built with Hugo that uses the ‘standard’ YAML frontmatter format with just two separating sets of dashes unlike Kirby which separates every field with dashes. Is there anyway I can bulk convert/import my old articles that use the ‘standard’ format into Kirby’s format?

With Data::read() and type yaml, you can read your original yaml data.

Then to create pages for Kirby, you would use Page::create(), rather than writing the files. This method creates the page folder and the content file for you.

Thanks for the response.

I took a look at the docs for those commands but I’m unsure how exactly I need to use them.

Can I simply upload my existing yaml files to a folder on my server and then run them from a php file?

to explain a bit more… kirby stores its content in txt files with yaml content. to convert your *.md/yaml frontmatter files you need to create new pages from them. you could loop over all files and read them creating new pages with their content. you can call that code anywhere but i would suggest a route which you can call like example.test/import/hugo in you browser.

something like that but i did not add a recursive loop for subfolders.

site/config/config.php

<?php

return [
  // other options
  'routes' => [
    [
      'pattern' => 'import/hugo',
      'action' => function () {
        $dir = kirby()->roots()->index() . '/hugo'; // put your files here
        foreach (Dir::files($dir) as $file) {
          if (F::extension($file) !== 'md') continue; // or yaml depending on you hugo setup

          $yaml = \Kirby\Data\Data::read($file, 'yaml');
          // create pages at root level
          site()->createChild([
            'slug' => $yaml['slug'],
            'template' => 'default',
            // everything...
            // 'content' => $yaml,
            // ...or one by one in case you need to change them a bit
            'content' => [
              'title' => $yaml['title'],
              'text' => $yaml['text'],
              'date' => $yaml['date'],
              // ...
            ],
          ]);
        }
      },
    ],
  ],
];

Thanks for the detailed code.

I’m now encountering an error: Kirby\Exception\Exception thrown with message “The file “xyz.md” does not exist or cannot be read”

The ‘standard’ front matter md files are in a /hugo folder and the route has been created per your code in config.php

A while ago I asked about automating conversions from standard yaml to Kirby front matter on this thread. I did receive helpful responses but the solution doesn’t seem to be working, no doubt because of my limited knowledge of PHP.

Having moved my standard yaml files in .md format to a ‘Hugo’ folder in the document root, and having copied the following code (thanks to Bruno Meilick for the original code found in the link above) to site/config/config.php (which didn’t exist, I created it)—

<?php

return [

  'routes' => [
    [
      'pattern' => 'import/hugo',
      'action' => function () {
        $dir = kirby()->roots()->index() . '/hugo';
        foreach (Dir::files($dir) as $file) {
          if (F::extension($file) !== 'md') continue;

          $yaml = Data::read($file, 'yaml');

          site()->createChild([
            'slug' => F::filename($file),
            'template' => 'default',
            'content' => $yaml,
          ]);
        }
      },
    ],
  ],
];

I visit website.test/import/hugo as per the pattern in the route and receive this error:

Kirby\Exception\Exception thrown with message “The file “test.md” does not exist or cannot be read”

(test.md is the correct name of the only file in the Hugo folder mentioned above, so it does detect the file)

Stacktrace:

#8 Kirby\Exception\Exception in <--file path-->/kirby/src/Data/Handler.php:41
#7 Kirby\Data\Handler:read in <--file path-->/kirby/src/Data/Data.php:101
#6 Kirby\Data\Data:read in <--file path-->/site/config/config.php:13
#5 Kirby\Http\Route:{closure} in [internal]:0
#4 Closure:call in <--file path-->/kirby/src/Http/Router.php:120
#3 Kirby\Http\Router:call in <--file path-->/kirby/src/Cms/App.php:337
#2 Kirby\Cms\App:call in <--file path-->/kirby/src/Cms/App.php:1191
#1 Kirby\Cms\App:render in <--file path-->/index.php:5
#0 require in <--file path-->.composer/vendor/laravel/valet/server.php:110

I suspect the Data::read function has no way to know which folder you’re currently thinking of, so doing Data::read('test.md', 'yaml') will maybe look at C:\test.md (or /test.md on Linux and macOS)?

You probably need to provide a full path to that file:

$yaml = Data::read("$dir/$file", 'yaml');

Though I’m not sure that a Markdown file with YAML frontmatter can be parsed as a YAML document. The YAML format supports multiple documents separated by --- in a single file, so if you have something like this:

---
title: Hello
tags: foo, bar, baz
---

# Hello World!

How are you doing?

A YAML parser would see this as 2 documents, and parse the first one correctly but fail on the second one because:

  • # Hello World! will be parsed as a comment, so that’s ignored, but
  • How are you doing? is invalid YAML syntax

So you would need to read the file as a string, extract the YAML frontmatter section only, and parse that as YAML.

There is an error in the code, Data::read expects the path to the file:

$yaml = Data::read($dir . '/' . $file, 'yaml');

Oops, too late to the party…

To extract the YAML front-matter from a Markdown file, you can probably find a good package by looking on Packagist (the package repository used by Composer):

Even if you don’t use composer and don’t install one of those packages directly, you can look at their source code on GitHub to check what they’re doing, and maybe copy the relevant parts.