JSON and the WP REST API

This post is supporting a bunch of tweets going out for pressedconf22 on March 24.

Why?

The basic idea is that WordPress is good for taking care of the mechanics of writing on the Internet. It deals with users, logins, uploading media, writing to the database, etc. On the other hand, WordPress themes can feel really big and confusing depending on what you’re trying to do and your experience. WordPress’s REST API is one path to a fairly simple, javascript-first method for interacting with the data in your site. It’s also great if you want to avoid PHP.1 You might see sites like this described as headless WordPress.2 Maybe you just want to make a headless site because the name sounds cool. Why not? Have some fun with your life.3

Please keep in mind, people could angrily argue for hours about any of these points and I’d just shrug. These aren’t eternal truths or things I’d go to war for. I’m just describing how I think about it and that thinking could very well change as time passes, technology shifts, or I learn more.

Examples

I’ll give a quick overview of some projects using the WordPress API below and then explain technically how they work better as we introduce some of the concepts involved in working with the API. It is worth noting that these sites just display information. I’m not using the API to create or edit content (both of which are possible). In addition to my examples below, you might want to check out this Torque post showing seven much more sophisticated examples of headless WordPress.

A screenshot of the cyber security website showing a card with text.

Cyber Security Card Game

This site is composed of only two page templates- the home page where the majority of the game is played and then a question page that contains additional information on the topic. You can see how most WordPress themes would be giving us a lot more by default and I’m not really using the data in the way that most sites are optimized for. Could I build this in a WordPress theme and have it basically be indistinguishable? Sure. It just felt like it would take longer and be more complicated.

Cyber Card Deck

The WordPress API interaction on the home page is centered on getting the “cards” (a custom post type) and building in interactions to restrict the what card data is retrieved through various taxonomies. Clicking on the top card randomizes a card from the data you’ve chosen to load.

Card Resource Page

Clicking on “learn more” when you’ve drawn a card will take you to a new template. The URL would be something like https://alplearn.com/extras/cybersecurity/resources.html?id=46. You can see that the ID of the card is the URL and that ID is used to fetch the data for that card for display. It has some fallbacks to put “coming soon” text as the project is still in very early days.

A screenshot of the digital detox site.

Digital Detox

I wrote up the Detox site more completely a while back. The focus of that post was more on performance/energy efficiency. That’s another aspect of using the API data that might be worth thinking about. It can provide some ways to really pare down what gets loaded and what needs to be cached. You can certainly do that in a regular WordPress theme but I find it easier to understand and implement in this scenario without using third-party services.

This site uses pretty much the same pattern4 as the Cyber Security Card site. It has a main index page and then a page for each article. It’s actually so similar as to be kind of boring. Sorry about that. I’ll make a major shift in the next example.

A screenshot of Timeline JS showing content provided by WordPress's post data JSON.

Timeline JS Integration

Given there are lots of javascript tools out there, it is much easier to take JSON (as opposed to xml) and use that with these tools. In this example, I’m displaying the WordPress posts JSON in Timeline JS. So it’s not so much headless WordPress as being able to take data from WordPress and display it in ways that provide different functionality without having to build those views yourself. Your WordPress site could continue using a normal theme but still take advantage of the flexibility of data provided by the API. I think that’s really powerful and especially interesting for educators who might want to shift understanding by providing information in a variety of visual environments that support different kinds of understandings. For me, that’s one of the most beautiful aspects of digital data.

What is JSON?

The easiest definition for me is that JSON is just a standard pattern for writing data. Just like XML or CSV. I tend to associate it with javascript but you can use it with pretty much any language. That’s probably good enough for our purposes. I do suggest you add an extension to your browser to format the JSON you see. It makes it much easier to figure out what’s going on and is a really good example of how visualization of the same data can alter your ability to understand it.

See the difference in these two examples of the same data. One is formatted, the other is not.
Unformatted JSON showing how it's hard to read and parse structure.

Formatted JSON showing the nested aspect of the data.

Fetch – Getting the JSON

I use fetch to get the JSON data. In this example, we are getting the post data from the pressedconf site but we could get pages, basic site information, or any number of things. The javascript that does the work is below.

fetch('https://pressedconf.org/wp-json/wp/v2/posts')
.then(response => response.json())
.then(data => console.log(data));

Play around with this example on CodePen.

Display the JSON

Now we can move from showing the JSON content in console to displaying select pieces of the data via a function that we write.

In this example using the showMeTheData function, we are getting the title (item.title.rendered) and the post link (item.link) to fill in some HTML to make a link back to the original content. That content is then displayed in the div with the id of “put-it-here.”

You can see below that the fetch has only changed slightly. I’ve changed the URL to only get two posts because I wanted to keep that fairly clean in case you were looking at the data. The other change is to move from logging the data to the console (console.log) to using a function to write the data to a div on the page.

fetch('https://pressedconf.org/wp-json/wp/v2/posts?per_page=2')
  .then(response => response.json())
  .then(data => showMeTheData(data));

The only HTML that matters is a div with the ID we are looking for (put-it-here);

  <div id="put-it-here"></div>

Now let’s take a look at the function that parses and writes the data.

function showMeTheData(data){
  const destination = document.getElementById('put-it-here');
    data.forEach((item, index) => {
      const title = item.title.rendered;
      const link = item.link;
      destination.innerHTML += `<a href="${link}">${title}</a>`;
  });
}

We’re passing ‘data’ in as a variable. That’s the (data) portion and we do that when we use it as part of fetch.

The next thing we do is get the div that we want as the destination. There are a number of ways to do this. For instance, these two things do the exact same thing.

  const destination = document.getElementById('put-it-here');
  const destination = document.querySelector('#put-it-here'); 

Now that we have our destination, we can do things to it.

So let’s set up a loop to write some content. data remains our big blob of JSON from WordPress and in it we have two5 big chunks of data representing two posts. We want to loop through that data and pick particular elements to write to our page.

function showMeTheData(data){
  const destination = document.getElementById('put-it-here');//we just talked about this, provided only for context
    data.forEach((item) => {
      const title = item.title.rendered;
      const link = item.link;
      destination.innerHTML += `<a href="${link}">${title}</a>`;
  });
}

In the forEach loop, “item” is just a random variable name. It could be “post” or “fish” or “magicBean.” It isn’t an element reflected in the JSON data. It’s just a pointer to the top-level pieces. Whatever you decide to use is important though as that word becomes the initial navigation point for moving through the JSON pieces (item.title.rendered).

JSON data displaying how nesting works. The first element is indicated by a curly bracket. Then within that bracket are names which may or may not have sub-elements. They are addressable by chaining terms with periods. For example, item.title.rendered.

In our example function, we are getting the title and link from the JSON data. The link is only one level in. So we can get it with item.link. The title is two levels in and we get it by appending the additional name to get to the data we want- item.title.rendered.

function showMeTheData(data){
  const destination = document.getElementById('put-it-here');//we just talked about this, provided only for context
    data.forEach((item) => {
      const title = item.title.rendered;//gets the title
      const link = item.link;//gets the link
      destination.innerHTML += `<a href="${link}">${title}</a>`;
  });
}

We now have the specific data we want and a destination. Writing to the div could be done in many ways but I’m going to use javascript template literals. Note that those are not single quotes but backticks. There’s a pretty good explanation of why you might want to go this route here.

      const title = item.title.rendered;//gets the title
      const link = item.link;//gets the link
      destination.innerHTML += `<a href="${link}">${title}</a>`;//this write the actual content and is just adding it to the innerHTML of the div

I’ve got another example in CodePen if you want to try modifying things.


1 I don’t mind PHP but I will catch myself trying to do PHP patterns in javascript and vice versa which is a little annoying.

2 I’m linking to Jeff’s article. We worked at VCU together and he’s since moved on to work for WPEngine.

3 If I were a better blog post writer the title of this post would reference Jason and Argonauts, the four horsemen of the apocalypse, the headless horseman, or better yet, a combination of all three.

4 That means it’s either a useful pattern or I lack imagination. If it’s the latter I probably lack the ability to realize it.

5 Only two because we limited things with the way we wrote the JSON URL–https://pressedconf.org/wp-json/wp/v2/posts?per_page=2. We can go up to 99 without having to adjust things manually on the WordPress side.