I know I’ve been talking about Hugo a lot, but the whole reason I say and wrapped my head around it was that I wanted to make a website using JSON.

Making something out of the JSON API in WordPress isn’t easy, and I decided to start with something hard. I thought I would make a Multisite network to be the back end of my site, and then call the JSON API to generate the content.

Why?

It doesn’t make my site (much) faster, though it makes it more cacheable. Mostly what it does is lets me separate church and state. I can use WordPress to write content, and then call it however I want. That would be Hugo. If I build the site via Hugo locally, then every time I generate the files it can pull in the data on the fly.

Enable the API

This is easy. Install WordPress 4.4 and install v2 of the Rest API plugin. I also installed Jetpack for reasons of using Calypso.

You absolutely have to use the Rest API plugin. WordPress 4.4 adds in some of the bits, but the API plugin gives you the actual endpoints. You’ll need these later.

Call the API

This was also easy. Kind of. Making a jquery file that called the content was fairly straightforward but… Making it responsive and reactive was hard.

What I really wanted to do was have some web app, js powered without node, that just called the data and kept the url structure. And for that what I need is a JSON client.

It was incredibly hard to find how to make a static HTML website powered by JSON. I’d see Rachel Baker’s presentation on making a WordPress theme with the JSON API but that wasn’t what I wanted to do. I mean, in a way it was. The theme itself was what I wanted, but I didn’t want to run it with WordPress.

I did a lot of research and finally stumbled onto restful.js by marmelab. I read their blog post on the product and it looked like what I wanted. I needed something that would run without Node.js since I wanted to do this on Apache.

Consuming a RESTful Web Service Dynamically

And this is when I starting banging my head against a table. None of the solutions I’d found were working for me. Nothing. Rachel was right. I was in a bit over my head. Oh she was nice enough not to say it that way, but they way she looked at me was very Jewish Mom of her.

In order to stop feeling useless, I decided to learn Hugo. It had come up a few times on my search for a dynamic static site. Hugo has LiveReload which, if you’re familiar with most static generators, is pretty cool. The idea is the pages rebuild as you edit the content (or theme) files.

If you run hugo server locally on your laptop, you can see this today. Hugo upped the ante by tossing in the ability to run it on the server and the ability to watch the data files. It also has the ability to call JSON remotely.

I feel it’s important to note that you cannot trigger that LiveReload when you’re using external URLs. But anytime you edit a file and LiveReload is triggered, Hugo will read the URL content from your cache. If you’ve disabled cache, it will download it fresh. Don’t disable cache unless you have an unlimited API. And no, I don’t know how long the cache is good for.

Sadly, OAuth or other authentication methods are not working yet, but for now that’s okay because I’d been in over my head for so long, I stepped back.

Understanding JSON First

Okay fine. Once I realized I’d tried to do too much at first, I went back to that static filmography I had.

  {
  	"role": "actor",
    "title": "White Christmas",
    "slug": "white-christmas",
    "type": "Movie",
    "character": "Phil Davis",
    "notes": null,
    "dates": 1954
  }

This is basic stuff. A simple chunk by chunk. And to call the file in a shortcode, I did this:

{{ range $.Page.Site.Data.filmography }}
	{{ if eq $role .role }}
		<li>{{ .title }}: <strong>{{ .character }}</strong> </li>
	{{ end }}
{{ end }}

Actually I did a lot more but you get the idea. And if you’re wondering about the if statement at the top, it’s so I can pass a parameter to my shortcode:

{{< filmography role="actor" >}}

It took me longer than I’d like to figure that out. At first I had multiple filmography files (actor, writer, producer) and I was trying to look through them all. In the end, I realized this simple JSON and a simple call was better.

A Little More JSON

There was another case, though. I had lists of episodes compiled into separate JSON files, one per show. This is logical and maintainable after all, but it meant I couldn’t use the same logic loop in the same way.

What I really needed was to loop through $.Page.Site.Data.episodes.SHOWNAME in order to get the data from that show. And I couldn’t add on a variable to my range call.

But as it happens, Hugo is clever and if I say {{ range $.Page.Site.Data.episodes }} it will give me the file episodes.json if that exists. But if there happens to be a folder called episodes then it will give me all the JSON files in there.

I read through the data documentation on Hugo a few times to understand the hierarchy but it breaks down really logically:

├── data
|   ├── episodes
|   |   ├── continum.json
|   |   └── fringe.json
|   |   └── sense8.json
|   ├── movies.json
|   ├── musicals.html

Data {dot} episodes {dot} continum

And if I ran this:

{{ range $.Page.Site.Data.episodes }}
	<li>{{ .show }}<li>
{{ end }}

Then I got this:

  • continum
  • fringe
  • sense8

I already knew I could do a range within a range, and finally I came up with this:

{{ $show := $.Page.Params.show }}

{{ range $.Page.Site.Data.episodes }}
	{{ if eq .show $show }}
		<li>{{ .title }}</li>
	{{ end }}
{{ end}}

The shortcode checks the post it’s on and, if the Front Matter has ‘show’ defined, it will give me a list of all titles (episode titles) for that show.

I added in an extra check for the season parameter. This one is passed through the shortcode:

{{< episodelist season="1" >}}

And that, in turn is called in the shortcode above the output for title:

{{ range where .episodes "season" "==" $season }}

So nothing will display unless the show in the JSON file matches the show on the page with the shortcode, and the season matches the one defined in the shortcode.

Now I actually have a more robust check. If no season is defined, it shows all episodes (useful for one-season shows, right?). But you get the idea.

How Did This Help?

Remember my JSON example before? Here’s what it looks like for Fringe:

{
"show" : "fringe",
"episodes": [
  {
    "epnum": "1",
    "season": "1",
    "title": "Pilot",
    "slug": "pilot",
    "airdate": "2008-09-08T22:00:00.000Z",
    "rating": "5",
    "summary": "Walter gets a cow named Gene to experiment on ethically."
  },
  ...
]}

Instead of just started with those naked chunks, I have a definition of the show name (fringe – lowercase because I want to compare it to other lowercase things and I’m lazy) and the definition of a section for episodes. That’s the whole reason why that call for seasons works the way I want it to.

This helped me to understand and visualize JSON. By taking a simple JSON list (the filmography) I learned the basics of connecting code and content. Then by taking the more complex scenario, where I needed nested data, I understood that relationship.

The next step will be making a simple WordPress site and calling the JSON remotely. Obviously I have to figure out how to trick it into making fake permalinks, but baby steps. Baby steps.

Reader Interactions

%d bloggers like this: