From Wordpress to Kirby - Part 2: Migrating Data

In this series, I document the process of switching the WeedPornDaily CMS from Wordpress to Kirby. If you missed Part 1 of our Wordpress to Kirby series, make sure to check it out, it discusses the architecture and planning behind the move.

So after figuring out the CMS, the sitemap, and designing the website -- we can finally start the careful process of migrating the site data. For WPD's stack, we use Wordpress with a couple extra plugins to create custom post types. The main content we were after was the blog and event calendar posts. We also needed the website media files, since Wordpress keeps it's images in it's own associative table.

Converting Wordpress XML to a Flat-File Structure

After determining what data we needed, I began the search for a possible conversion or migration script (never re-invent the wheel). I stumbled upon a script called WPXML to Kirby written by greywillfade on Github. It works by taking your basic Wordpress XML export and generates TXT files in the Kirby format.

Adding Images to the Export

It worked great, except none of the posts imported with images. Because Wordpress stores images in a separate table, they export in a separate XML file. After spending 10 minutes trying to combine both RSS feeds inside the script, I opted for a quicker, dirtier method: editing core WordPress files. I peeped inside wp-admin/includes/export.php and added the following snippet around line 544 underneath some XML elements Wordpress prints out:

After that, every RSS file you export will have the associated featured image. It works with posts, events, any custom post type utilizing WordPress' post_thumbnail functionality. This is documented on our Github if you're interested in implementing.

Gotta Have Events

WeedPornDaily uses The Events Calendar plugin by Modern Tribe to manage and show events on the website. It's pretty easy to export the events, you can use the default export section a WPXML file with only event posts. And since it's WPXML, we can use the same script, with a little modification

All the event data we're looking for is stored inside XML namespaces. The original script author thought of this, and added a namespace array to the beginning of the script. It makes accessing namespaces as easy as $item->children($ns['wp'])->postmeta.

The event data is stored in WordPress as post meta, with a key and value. The post meta is printed in the XML file as repetitive containers with the key and value as the child elements. So you don't know what you're looking for unless you load all of them. To find our event data, we cycle through each post meta and see if the key matches our criteria:

You can find the full code on our Github here. I'd never used XML namespaces before, so it was a nice exercise in extracting data from them.

Where do you go? My data?

You might be saying, "Hey wait, you're adding data to your CMS, but where is it going? Kirby only has out-of-the-box support for blog posts." Part of the planning that went into designing the website and UX, was determining the structure of each post type. In the Sketch file, I broke down every type of post we'd have, from blog posts to events to videos to GIFs to podcasts, and decided what data we'd need from each.

Making the posts

This translated perfectly to Kirby's blueprint system, which creates posts based on YAML files. I created a blueprint for each post type, including events, and made sure it lined up with the data from the conversion script. In this case, it was fine tuning how category data was stored (categories are converted as full name, not slugs) and other small tweaks. The blueprint file I created is simply for creating posts via the backend admin 'Panel', and also helps you lay down concrete post variables.

For the events, I wanted things like the event start time, or the event location. Here's what we ended up with:

After the blueprint was made and I knew exactly what variables I was using, I started to create the template files that display the data on the front-end. With Kirby, if you want to create a new custom post type, you just create a file in the site/templates/ folder named your-custom-post.php and make a file in somewhere in your content folder (content/page/your-custom-post.txt). That's it. You can access any variable in your text file (variable_name: your data here) by accessing it through the page object ($page->variable_name()).

I opted to use snippets, another feature of Kirby, where you can make modular elements to include in template code. For the events page, I wanted to have a calendar on top showing a month view, and a list of the latest events underneath in a more classic post fashion. I created two snippets, one for the calendar, and one for the events feed (since it uses so many different variables/stylings than normal posts).

Creating the Calendar

A quick Google for "php calendar" and one of the first entries was the winner: an article by Xu Ding on Star Tutorial. I added his calendar class and base CSS to the snippet, and bam, we had a working calendar.

Upon inspection of the calendar class, I tried to think of the most efficient way to load the latest event data and disperse it amongst the appropriate dates. I settled on calling all the latest events posts, making an associative array with the event object data stored with the date as the key value. Then when the calendar calls it's function for displaying each date individually, I'd check for an event in the array, and display the event data if it matched the date.

In the class function that displays the calendar, key variables are defined at the start, such as the current year and month. I figured it'd be the perfect place to initialize my event data, so I placed the following underneath to create a class variable ($this->events) with an array of event data:

I query Kirby for the latest event pages. Querying posts in Kirby is usually as simple as (page('your-page')->children()->visible()->flip()). This pulls up 'your-page', grabs it's children folders (containing posts), and displays them. But we want to filter the data using one of the post's date variables, so we add a filter function to the end of the query. It returns only events with their end date greater than the first day of the current month.

Now we add the events to the actual calendar. Inside the _showDay class function, we add this bit underneath the date getting echoed:

It checks if the date exists as an key in the event array, then pumps out the event data. Since Kirby stores pages as referential objects, I can simply call the title() function to display the event's title.

Calendar Basically Done

Minus pagination - which got added in another round of development using Kirby's params and routes (a topic for a whole other article) - we're done. We have a working calendar that displays event posts. Once I imported the converted files, the events displayed without a hitch:


I also had to implement podcasts. They were done in a similar way, creating a blueprint, template, and snippet files. When it came time to generate an iTunes friendly podcast feed, I printed one out in PHP.

What was unique about podcasts, was the necessity to generate a filesize and time length for the audio files. The iTunes XML file requires it, and we never expect someone to manually input something like that, so we created a quick Kirby plugin to solve the issue.

The plugin basically checks if you're saving a page with a field called MP3. If you are, it runs a PHP script to load the MP3 file and determine it's filesize and length. Then it adds both variables to your podcast post TXT file. Simple, effective, and just what we needed. It adds no load time to the backend, except when processing audio files.

More to come!

We've created all the necessary post types, created a conversion script for all our data, and migrated it. Next time I'll talk about how we integrate Tumblr into the site, syncing and converting Tumblr data to Kirby, and the future features we plan on implementing. Catch all that and more in Part 3 of our guide coming soon!

Stay regular,

Further Reading:

-WPXML to Kirby
-Our Fork of WPXML to Kirby
-Wordpress function - the_post_thumbnail()
-Calendar Tutorial by Xu Ding
-Calculate Duration of MP3


Oscar is an artist and engineer who's been creating cannabis brands and media experiences for over 10 years, and developing full-stack applications for over 15 years.