How to use the WordPress REST API to inject blog posts into a separate website

If you have a WordPress site with content published, you can programmatically access your posts using the built-in REST API.

This is super useful if you want to build a “Recent Blog Posts” widget, for example.

WordPress makes this easy with their REST API.

All it takes is some basic JavaScript skills and some patience.

Let’s take a look at what’s needed.

  • A WordPress (v. 4.7 or higher) site with content. (If you don’t have a WordPress site, feel free to use this site to follow along with this post.)
  • Access to a separate website’s code.

That’s it. Let’s get started.

Locate the endpoint

The most important thing about this tutorial is how to find the REST API endpoint. It’s not exactly obvious.

Take the base url of your WordPress website (or mine, if you don’t have your own) and add the following string to it /wp-json/wp/v2/posts.

Enter it into your browser.

It will return JSON data for the blog posts on the WordPress website.

This is the endpoint we will be using in our JavaScript to build the widget.

Open a CodePen and fetch posts

Let’s use CodePen for the site where we’ll build the widget. In a real use case, you’ll just inject the JavaScript where ever it is you want the widget.

In our JavaScript, let’s focus first on pinging the endpoint and logging the response. We’ll use the “modern” approach to client-side API consumption by using the Fetch API with async await syntax.


  async function fetchPosts() {
    const response = await fetch('https://www.codeandtell.blog/wp-json/wp/v2/posts');
    const posts = await response.json();
    return posts;
  }

  fetchPosts().then(posts => {
    console.log(posts);
  });

Let’s unpack what’s going on here. We define an async function called fetchPosts. In it, we fetch data from an endpoint, and convert it from JSON to a JavaScript object we can later parse. This object is returned from the async function as a promise that must be resolved or rejected. (Async functions always return a promise.) When we call the async function, we use the then method to handle the promise. In the body of this callback function block, we can then finally do stuff with our data, like log it to the console. Save this code in CodePen. In CodePen’s console, you should see a JavaScript array with the post data. (It may look like JSON in the CodePen console, but it’s not. Try checking the actual Chrome console and you’ll see what I mean.)

Handle errors with a try-catch block

Now that we got it working, let’s add some error handling, just to do our due diligence. For example, in case something were to change about our endpoint and the url was structured differently by WordPress.


  async function fetchPosts() {
    try {
      const response = await fetch('https://www.codeandtell.blog/wp-json/wp/v2/posts');
      const posts = await response.json();
      return posts;
    } catch (error) {
      console.error('fetching error: ', error);
    }
    
  }

  fetchPosts().then(posts => {
    console.log(posts);
  });

Let’s mess up the endpoint’s URL to see if we’re throwing an error. Misspell ‘json’ as ‘jsun’ like so:

https://www.codeandtell.blog/wp-jsun/wp/v2/posts

Our fetching error: should now appear in the console as expected. Nice!

Planning the widget

Now, let’s think about what we actually want to do with the data from the endpoint. If we’re building a Recent Blog Posts widget, like the one I built for my portfolio, we need to iterate through the list of posts, and for each one, create HTML elements, populate them with the data we’re interested in, and append them to a container <div>. And then we can style it as needed.

Let’s start by defining an empty container <div> in our CodePen html. Let’s give it an id of "app". We’ll come back to this later.

Looking at our array of posts in the console, we can identify three pieces of data that will be relatively easy to parse: the title, the post URL, and the excerpt. The excerpt is a better choice than the full content in this instance because it gives the reader a taste of the content while being short enough to fit into the piece of UI appropriate for one of these widgets.

So we want to have a piece of html for each post that contains:

  • a wrapping <div> that represents the post as a discrete piece of UI
  • a wrapping <a> with an href of the post URL
  • a heading (let’s just say <h3>) for the post title
  • a <p> for the post excerpt (snippet)

Where do we do this in our JavaScript?

We’re going to write all of this code inside the then callback function block, since that’s where our workable JavaScript array lives.

fetchPosts().then(posts => { // write our code in here });

Iterating through posts

Okay, but what JavaScript will we actually write?

Let’s start by iterating through our list of posts.

We can use an array method called forEach to start doing start doing stuff with each post in the posts array.

It will look like this:

posts.forEach(post => { // do stuff with the post in here });

Creating HTML for each post

Now that we’re working with each post individually, we’ll want to create some HTML using the createElement function. This is a method of the document object and takes a string with the name of an HTML element as an argument.

For our first bullet point, let’s make a <div>:

const postEl = document.createElement('div');

For our second bullet point, let’s make an <a>:

const linkEl = document.createElement('a');

For our third bullet point, let’s make an <h3>:

const titleEl = document.createElement('h3');

For our fourth bullet point, let’s make an <p>:

const excerptEl = document.createElement('p');

Now, let’s get the data into these elements where it belongs.

Just to make sure we’re on the same page, let’s zoom out and look at our code so far:


  async function fetchPosts() {
    try {
      const response = await fetch('https://www.codeandtell.blog/wp-json/wp/v2/posts');
      const posts = await response.json();
      return posts;
    } catch (error) {
      console.error('fetching error: ', error);
    }
    
  }

  fetchPosts().then(posts => {
    posts.forEach(post => {
      const postEl = document.createElement('div');
      const linkEl = document.createElement('a');
      const titleEl = document.createElement('h3');
      const excerptEl = document.createElement('p');
    });
  });

Adding data to our JavaScript-generated markup

For our <a>, which we defined in JavaScript as a variable called linkEl, we are going to put the URL in an href attribute.

So let’s figure out how to target that URL and get it into an href on linkEl.

In our post object data, there’s a top-level property with a key of “link”. This means that inside our loop, we can access it with dot notation by referencing post.link. The value is a string with the post URL.

Meanwhile, we can can set an attribute on an element with JavaScript with the setAttribute method. It takes two string arguments: the first one being the key of the attribute and the second one being the value we want to set for it.

So we can write this JavaScript to set our linkEl href with the post URL:

linkEl.setAttribute('href', post.link);

Let’s look now to the title.

The post’s title key is at the same top-level of the post object, so we can access its value by referencing post.title. However, if we inspect the data more closely, that value is not a string, but an object. So we need to refer to post.title.rendered to get the actual title string.

To get that into our titleEl html, we don’t need a method. We can just do something like this:

titleEl.textContent = post.title.rendered;

And we can do the same thing with the excerpt as well:

excerptEl.textContent = post.excerpt.rendered;

Append html elements to parent elements

Now it’s time to start defining the structure of our markup we’ve just created.

The way I see this fitting together is as follows

Our <div id="app></div> that we defined in the CodePen HTML is the container for each postEl, which is the container for linkEl, which is the container for both titleEl and excerptEl (these two are siblings of each other). So the structure looks something like this:

  • #app
    • postEl
      • linkEl
        • titleEl
        • excerptEl

Let’s start at the innermost level and work our way outwards with our JavaScript.

To add titleEl and excerptEl to linkEl, we can use the append method. The method is called on the element that is having things appended to it. It takes the element that we’reĀ appending to it as an argument.

linkEl.append(titleEl);

linkEl.append(excerptEl);

Now that we have established parent-child DOM relationships between linkEl and titleEl and excerptEl, we can do the same with postEl and linkEl.

postEl.append(linkEl);

Append JavaScript-generated markup to the DOM

Now we have to select our #app and append postEl, which now contains all our JavaScript-generated markup for the post within.

document.querySelector('#app').append(postEl);

This last step is what actually brings all our JavaScript-generated markup into the actual DOM of our website. So don’t forget to do it!

Our JavaScript file will now look like this:


  async function fetchPosts() {
    try {
      const response = await fetch('https://www.codeandtell.blog/wp-json/wp/v2/posts');
      const posts = await response.json();
      return posts;
    } catch (error) {
      console.error('fetching error: ', error);
    }
    
  }

  fetchPosts().then(posts => {
    posts.forEach(post => {
      const postEl = document.createElement('div');
      const linkEl = document.createElement('a');
      const titleEl = document.createElement('h3');
      const excerptEl = document.createElement('p');
      linkEl.setAttribute('href', post.link);
      titleEl.textContent = post.title.rendered;
      excerptEl.textContent = post.excerpt.rendered;
      linkEl.append(titleEl);
      linkEl.append(excerptEl);
      postEl.append(linkEl);
      document.querySelector('#app').append(postEl);
    });
  });

You should now see your blog post data as the rendered HTML we specified in our JavaScript.

Remove and replace unwanted strings from HTML

You may notice a couple things.

  • There’s a <p> tag wrapping the excerpt.
  • There may be some nonsense-looking substrings in the title and/or excerpt.

We can make quick work of these by using the replaceAll method and repeatedly chaining it to (post.title.rendered) and (post.excerpt.rendered).

Let’s start by getting rid of the <p></p> in the excerpt.

Modify the line of code pertaining to the excerpt data so it looks like this:

excerptEl.textContent = (post.excerpt.rendered).replaceAll('<p>', '').replaceAll('</p>', '');

To fix the nonsense looking substrings, you can refer back to your WordPress content, and decipher the character that should be where the substring is. Once you’ve identified it, you can put in as the second argument of a replaceAll call, where the first argument is the nonsense-looking substring in question.

For my excerpt, this code seems to clean them up well for now:

excerptEl.textContent = (post.excerpt.rendered).replaceAll('<p>', '').replaceAll('</p>', '').replaceAll('&#8211;', '-').replaceAll('&#8217;', "'").replaceAll('&hellip;', "...").replaceAll('&#8220;', '"').replaceAll('&#8221;', '"');

And for my title, this did the trick (for the time being):

titleEl.textContent = (post.title.rendered).replaceAll('&#8211;', '-').replaceAll('&#8217;', "'");

Looks ugly, but it does the job for now!

As you write more posts, be sure to check in on the output of your widget. You’ll be adding more chained instances of replaceAll as you use more characters that show up as these unicode decimal strings. It’s going to be some tedious trial and error, but the principle is pretty simple: replace the thing you don’t want with what it was supposed to be!

Congrats, you now have a widget you can add to your website that features your recent WordPress blog posts!