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 anhref
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('–', '-').replaceAll('’', "'").replaceAll('…', "...").replaceAll('“', '"').replaceAll('”', '"');
And for my title, this did the trick (for the time being):
titleEl.textContent = (post.title.rendered).replaceAll('–', '-').replaceAll('’', "'");
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!