New year, old problems, new Website -- this was my reasoning during the christmas holidays, and so I decided to completly wipe my "About me" website, making it a simple hub of my diverse activities and interests instead of the old "hey, look how cool experienced I am, come work with me and give me all your money" thing.
I decided to build the site with Kirby, a lovely file based CMS which I have used in the past (for example to drive our Frankfurt Open Device Lab website). Kirby is very flexible, has a stellar documentation, a nice API, and makes zero assumptions on how you want to build your site, and besides being file based, it offers a very customizable backend, if need be.

Now, one of the things I wanted on the new site was a way to display the latest posts from here, my blog, but only those relating to the topics of Design, Webdevelopment and the like.

With a little bit of diving into the WordPress REST API, this turned out to be a fairly simple task for my Kirby-site. Basically this REST API allows me to "get" the infos needed on various objects of my WordPress site, by calling the API's entry points and telling it what I want.

A very basic call to get the latest post could be: https://www.webrocker.de/wp-json/wp/v2/posts/?per_page=1, which returns a JSON formatted string with plenty of info regarding that post (try it). Since the API has some sensible defaults regarding sorting and such, the only parameter needed is "per_page", to limit the amount of posts coming back.

For my Kirby site, I'd like to display the six newest posts, so the API call looks like this: https://www.webrocker.de/wp-json/wp/v2/posts/?per_page=6.
But I want to filter the posts first, and only fetch those with certain categories. Luckily, the API has a parameter for that as well: "categories". I could also negate that by using "categories_exclude", so I would get back posts without those who have the categories listed there applied. The "categories" (and "categories_exclude") parameter expects the internal IDs of the categories, not their name, so this bit needs to be researched in the WordPress backend. Well, not exactly, there is also an API endpoint to fetch category infos, so one could ask something like "gimme info on your categories named "foo", and check for "foo"'s ID in the returned JSON, but I skipped that.

So my call looks like this: https://www.webrocker.de/wp-json/wp/v2/posts/?per_page=6&categories=c1,c2,c3, where c1,c2,c3 are the IDs of my blog categories for Design, Web, and so on (obviously not the real IDs, just for illustration purposes).

So from the WordPress site with the build-in API everything is ready.

On the Kirby site, however, some more work needs to be done. I broke the tasks down to this:

  1. get the info from the WordPress blog
  2. store the returned json as file
  3. use that file as data-provider for the kirby template
  4. display the data on the "blog" section of the Kirby site

The straight-forward way would be like this: write some php in the "blog" template that fetches the response from the WordPress API, decode the JSON string into a php array, loop over the array and grab the data needed for the display: Most likely the title, the excerpt, the link. Since this would run everytime the "blog" section of the Kirby site is displayed, it would make a request over to my WordPress blog with every reload; that's not what I want.

So, I decided to off-load the "get the stuff from the API" part into a separate script. I decided to use a small shell script, since I have access via SSH and could easily call this script with a periodical or cron script on the server. But this could also be done in PHP, using the cURL or fopen functions or something similar.

// content/blog/json/blog.sh
#!/bin/bash
JSONFILE="./blog.json"
CATEGORIES="c1,c2,c3"
curl "https://www.webrocker.de/wp-json/wp/v2/posts/?per_page=6&categories=$CATEGORIES" -o $JSONFILE

My shell script makes the API request with curl, and saves the result in a blog.json file, that lives inside the /site/content/blog/json/ directory in my Kirby installation.

In my blog template, I check if this file is there, and then decode the string into a php array.
To keep my blog template clean, I wrote a small template controller for that, and put that in ```/site/controllers/blog.php```. If Kirby finds a template with the same name -- /site/templates/blog.php -- then the code in the controller is used before the rendering of the template and I can use the variables returned from the controller in my template code. (To find out more about how Kirby handles templates, controllers, snippets and much more exciting stuff, see the documentation)

// site/controllers/blog.php
return function($site, $pages, $page) {
	$posts = array();
	$json = __DIR__ . '/../../content/' . $page->dirname().'/json/blog.json';
	if( is_file($json) ){
		$contents = file_get_contents($json);
		$posts = json_decode($contents);
	}
	return [
		'posts' => $posts
	];
};

Alright, so let's use that in the template. I need to loop over the $posts array, and put out the things like title, content etc...
But, as I wrote earlier, I want the template file clean. So I wrote a snippet, which takes care of the looping etc stuff. Snippets in Kirby reside in /site/snippets and can be included with Kirby's snippet() helper function.

// site/snippets/posts.php
< ?php if(isset($posts) && count($posts) > 0): ?>
	<div class="posts">
		< ?php foreach( $posts as $post ):
			$title = $post->title->rendered;
			$link = $post->link;
			$content = $post->excerpt->rendered;
			$footer = '<p class="post__footer">(<a href="' . $link . '">read on</a>)</p>';
			if(in_array($post->format,array('video'))){
				$content = $post->content->rendered;
				$footer = '';
			}
		?>
		<div class="post">
			<h3 class="post__heading"><a href="<?= $link ?>">< ?= $title ?></a></h3>
			<div class="post__content">
				< ?= $content ?>
			</div>
			< ?= $footer ?>
		</div><!-- .post -->
		< ?php endforeach; ?>
	</div><!-- .posts -->
< ?php endif; ?>

And now finally, this is used in the blog template file:

< ?php snippet('header'); ?>
 
<main role="main" class="page__main wrap wide">
	<h2>< ?= $page->title()->html(); ?></h2>
	<div class="main-content">
		<div class="content__intro">< ?= $page->intro()->kirbytext(); ?></div>
		< ?php snippet('posts', array('posts' => $posts ) ); ?>
		< ?= $page->text()->kirbytext(); ?>
	</div><!-- .main-conent -->
</main><!-- .page__main -->
 
< ?php snippet('footer'); ?>

Here you also can see how Kirby makes it very easy to delegate variables from the template context to the snippet file, by using an associative array as the second parameter of the snippet() helper function.
Nice and clean.

So, that's all there is.

My next task will be to fetch the blog JSON periodically, or maybe even better, send a webmention from my blog to my Kirby site, which then will update the JSON when a new post is published.