How to make WordPress headless and fetch posts with JavaScript

Are you trying to make a headless WordPress site and using JavaScript to fetch the data?

If so, this the article you’ve been looking for then!

First, if you’re looking to launch a WordPress site for your blog or business, you might want to look into launching your blog with Bluehost for just $3.95/month. They make it really easy to select an affordable plan, and create or transfer a domain.

Get started with Bluehost.

Disclaimer: The two Bluehost links above are affiliate links which provide a small commission to me at no cost to you. These links track your purchase and credit it to this website. Affiliate links are a primary way that I make money from this blog and Bluehost is the best web hosting option for new bloggers.

If you’re looking for other options, check out this article, “Cheap hosting for WordPress blogs“.

Let’s dive into making a WordPress site headless.

WordPress is already headless

Out of the box, WordPress already provides a robust rest API.

You can visit the URL below to test that your your WordPress site rest API is available.


https://<replace-with-domain>/wp-json/

In this guide, I’m going to fetch the latest posts on a WordPress site. Here’s the endpoint that I will be requesting to return all the posts.

https://<replace-with-domain>/wp-json/wp/v2/posts

There’s 1 WordPress plugin I highly suggest you install. And that is called, Better REST API Featured Images.

Better REST API Featured Images will extend the Rest API posts endpoint and add the featured image urls.

This is helpful when you want to display your feature image on your JavaScript application or any other headless client app you’re building.

Here’s what the response from the plugin looks like.


"better_featured_image": {
    "id": 3118,
    "alt_text": "",
    "caption": "",
    "description": "",
    "media_type": "image",
    "media_details": {
        "width": 1024,
        "height": 768,
        "file": "2020/06/js-wp-fetch-posts.jpg",
        "sizes": {
            "medium": {
                "file": "js-wp-fetch-posts-300x225.jpg",
                "width": 300,
                "height": 225,
                "mime-type": "image/jpeg",
                "source_url": "https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/06/01121222/js-wp-fetch-posts-300x225.jpg"
            },
            "thumbnail": {
                "file": "js-wp-fetch-posts-150x150.jpg",
                "width": 150,
                "height": 150,
                "mime-type": "image/jpeg",
                "source_url": "https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/06/01121222/js-wp-fetch-posts-150x150.jpg"
            },
            "medium_large": {
                "file": "js-wp-fetch-posts-768x576.jpg",
                "width": 768,
                "height": 576,
                "mime-type": "image/jpeg",
                "source_url": "https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/06/01121222/js-wp-fetch-posts-768x576.jpg"
            }
        },
        "image_meta": {
            "aperture": "0",
            "credit": "",
            "camera": "",
            "caption": "",
            "created_timestamp": "0",
            "copyright": "",
            "focal_length": "0",
            "iso": "0",
            "shutter_speed": "0",
            "title": "",
            "orientation": "0",
            "keywords": []
        }
    },
    "post": 3084,
    "source_url": "https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/06/01121222/js-wp-fetch-posts.jpg"
}

If the post doesn’t have a featured image. The value will be null.


"better_featured_image": null

Now that all of that is setup, it’s time to get all the posts from your WordPress rest API.

Fetch WordPress posts with JavaScript

One way to fetch the posts with JavaScript is to make a request directly to the posts API endpoint.


async function fetchPosts() {
  try {
    const response = await fetch('https://<replace-with-domain>/wp-json/wp/v2/posts');

    console.log(response);
  } catch(e) {
    console.log(e)
    console.log(e);
  }
}

But that’s not a very efficient way to deal with the WordPress API.

Instead, install an NPM module called wpapi.


npm i -S wpapi

Here’s the JavaScript code to fetch the latest posts from your headless WordPress site with wpapi.


import WPAPI from 'wpapi';

// Create WPAPI instance and add endpoint to /wp-json
const wp = new WPAPI({
  endpoint: 'http://<replace-with-domain>/wp-json',
});

async function fetchPosts() {
 try {
  // Fetch posts
  const posts = await wp.posts().get();
  return posts;
 } catch (e) {
   // print error
   console.log(e);
   return [];
 }
}

The function above will either return an array of posts or an empty array if it fails.

It will print the error message out, in case you run into an error.

By default WordPress will return your latest 10 posts. If you want to fetch more than 10, then you may do so by using the perPage() chaining tool.


const posts = await wp.posts().perPage(20).get();

Here’s a sample WordPress response object:


[
  {
    "id": 3084,
    "date": "2020-06-01T12:26:38",
    "date_gmt": "2020-06-01T12:26:38",
    "modified": "2020-06-01T12:32:02",
    "modified_gmt": "2020-06-01T12:32:02",
    "slug": "how-to-make-wordpress-headless-and-fetch-posts-with-javascript",
    "status": "publish",
    "type": "post",
    "title": {
      "rendered": "How to make WordPress headless and fetch posts with JavaScript"
    },
    "content": {
      "rendered": "\n<p>Are you trying to make a headless WordPress site and using JavaScript to fetch the data?</p>\n\n\n\n<p>If so, this the article you&#8217;ve been looking for then!</p>\n\n\n\n<p>First, if you’re looking to launch a WordPress site for your blog or business, you might want to look into launching your blog with <a rel=\"noreferrer noopener\" href=\"/api/recommend/bluehost\" target=\"_blank\">Bluehost</a> for just $3.95/month. They make it really easy to select an affordable plan, and create or transfer a domain.</p>\n\n\n\n<p><strong>Get started with</strong> <a href=\"/api/recommend/bluehost\" target=\"_blank\" rel=\"noreferrer noopener\">Bluehost</a>.</p>\n\n\n\n<p><strong>Disclaimer:</strong> The two Bluehost links above are affiliate links which provide a small commission to me at no cost to you. These links track your purchase and credit it to this website. Affiliate links are a primary way that I make money from this blog and Bluehost is the best web hosting option for new bloggers.</p>\n\n\n\n<p>If you&#8217;re looking for other options, check out this article, &#8220;<a href=\"https://linguinecode.com/post/cheap-wordpress-hosting\">Cheap hosting for WordPress blogs</a>&#8220;.</p>\n\n\n\n<p>Let&#8217;s dive into making a WordPress site headless.</p>\n\n\n\n<h2>WordPress is already headless</h2>\n\n\n\n<p>Out of the box, WordPress already provides a robust rest API.</p>\n\n\n\n<p>You can visit the URL below to test that your your WordPress site rest API is available.</p>\n\n\n\n<pre><code rel=\"WordPress JSON endpoint\" class=\"language-text\">\nhttps://&lt;replace-with-domain&gt;/wp-json/\n</code></pre>\n\n\n\n<p>In this guide, I&#8217;m going to fetch the latest posts on a WordPress site. Here&#8217;s the endpoint that I will be requesting to return all the posts.</p>\n\n\n\n<p><code class=\"language-text\">https://&lt;replace-with-domain&gt;/wp-json/wp/v2/posts</code></p>\n\n\n\n<p>There&#8217;s 1 WordPress plugin I highly suggest you install. And that is called, <a rel=\"noreferrer noopener\" href=\"https://wordpress.org/plugins/better-rest-api-featured-images/\" target=\"_blank\">Better REST API Featured Images</a>.</p>\n\n\n\n<p>Better REST API Featured Images will extend the Rest API posts endpoint and add the featured image urls.</p>\n\n\n\n<p>This is helpful when you want to display your feature image on your JavaScript application or any other headless client app you&#8217;re building.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img src=\"https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/06/01111135/feature-img-field.jpg\" alt=\"\" class=\"wp-image-3092\" srcset=\"https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/06/01111135/feature-img-field.jpg 463w, https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/06/01111135/feature-img-field-300x189.jpg 300w\" sizes=\"(max-width: 463px) 100vw, 463px\" /></figure>\n\n\n\n<p>Here&#8217;s what the response from the plugin looks like.</p>\n\n\n\n<pre><code rel=\"Better REST API Featured Images response\" class=\"language-json\">\n&quot;better_featured_image&quot;: {\n    &quot;id&quot;: 3083,\n    &quot;alt_text&quot;: &quot;&quot;,\n    &quot;caption&quot;: &quot;&quot;,\n    &quot;description&quot;: &quot;&quot;,\n    &quot;media_type&quot;: &quot;image&quot;,\n    &quot;media_details&quot;: {\n        &quot;width&quot;: 1024,\n        &quot;height&quot;: 768,\n        &quot;file&quot;: &quot;2020/05/react-grid-layout-component.jpg&quot;,\n        &quot;sizes&quot;: {\n            &quot;medium&quot;: {\n                &quot;file&quot;: &quot;react-grid-layout-component-300x225.jpg&quot;,\n                &quot;width&quot;: 300,\n                &quot;height&quot;: 225,\n                &quot;mime-type&quot;: &quot;image/jpeg&quot;,\n                &quot;source_url&quot;: &quot;https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/05/30120740/react-grid-layout-component-300x225.jpg&quot;\n            },\n            &quot;thumbnail&quot;: {\n                &quot;file&quot;: &quot;react-grid-layout-component-150x150.jpg&quot;,\n                &quot;width&quot;: 150,\n                &quot;height&quot;: 150,\n                &quot;mime-type&quot;: &quot;image/jpeg&quot;,\n                &quot;source_url&quot;: &quot;https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/05/30120740/react-grid-layout-component-150x150.jpg&quot;\n            },\n            &quot;medium_large&quot;: {\n                &quot;file&quot;: &quot;react-grid-layout-component-768x576.jpg&quot;,\n                &quot;width&quot;: 768,\n                &quot;height&quot;: 576,\n                &quot;mime-type&quot;: &quot;image/jpeg&quot;,\n                &quot;source_url&quot;: &quot;https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/05/30120740/react-grid-layout-component-768x576.jpg&quot;\n            }\n        },\n        &quot;image_meta&quot;: {\n            &quot;aperture&quot;: &quot;0&quot;,\n            &quot;credit&quot;: &quot;&quot;,\n            &quot;camera&quot;: &quot;&quot;,\n            &quot;caption&quot;: &quot;&quot;,\n            &quot;created_timestamp&quot;: &quot;0&quot;,\n            &quot;copyright&quot;: &quot;&quot;,\n            &quot;focal_length&quot;: &quot;0&quot;,\n            &quot;iso&quot;: &quot;0&quot;,\n            &quot;shutter_speed&quot;: &quot;0&quot;,\n            &quot;title&quot;: &quot;&quot;,\n            &quot;orientation&quot;: &quot;0&quot;,\n            &quot;keywords&quot;: []\n        }\n    },\n    &quot;post&quot;: 3063,\n    &quot;source_url&quot;: &quot;https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2020/05/30120740/react-grid-layout-component.jpg&quot;\n}\n</code></pre>\n\n\n\n<p>If the post doesn&#8217;t have a featured image. The value will be <a href=\"https://linguinecode.com/guides/javascript/beginners/types-intro#null\">null</a>.</p>\n\n\n\n<pre><code rel=\"Better REST API Featured Images empty response\" class=\"language-json\">\n&quot;better_featured_image&quot;: null\n</code></pre>\n\n\n\n<p>Now that all of that is setup, it&#8217;s time to get all the posts from your WordPress rest API.</p>\n\n\n\n<h2>Fetch WordPress posts with JavaScript</h2>\n\n\n\n<p>One way to fetch the posts with JavaScript is to make a request directly to the posts API endpoint.</p>\n\n\n\n<pre><code rel=\"Fetch WP posts with JavaScript\" class=\"language-javascript\">\nasync function fetchPosts() {\n  try {\n    const response = await fetch('https://&lt;replace-with-domain&gt;/wp-json/wp/v2/posts');\n\n    console.log(response);\n  } catch(e) {\n    console.log(e)\n    console.log(e);\n  }\n}\n</code></pre>\n\n\n\n<p>But that&#8217;s not a very efficient way to deal with the WordPress API.</p>\n\n\n\n<p>Instead, install an NPM module called <a rel=\"noreferrer noopener\" href=\"https://www.npmjs.com/package/wpapi\" target=\"_blank\">wpapi</a>.</p>\n\n\n\n<pre><code rel=\"Terminal\" class=\"language-text\">\nnpm i -S wpapi\n</code></pre>\n\n\n\n<p>Here&#8217;s the JavaScript code to fetch the latest posts from your headless WordPress site with wpapi.</p>\n\n\n\n<pre><code rel=\"Fetch WP posts\" class=\"language-javascript\">\nimport WPAPI from 'wpapi';\n\n// Create WPAPI instance and add endpoint to /wp-json\nconst wp = new WPAPI({\n  endpoint: 'http://&lt;replace-with-domain&gt;/wp-json',\n});\n\nasync function fetchPosts() {\n try {\n  // Fetch posts\n  const posts = await wp.posts().get();\n  return posts;\n } catch (e) {\n   // print error\n   console.log(e);\n   return [];\n }\n}\n</code></pre>\n\n\n\n<p>The function above will either return an array of posts or an empty array if it fails.</p>\n\n\n\n<p>It will print the error message out, in case you run into an error.</p>\n\n\n\n<p>By default WordPress will return your latest 10 posts. If you want to fetch more than 10, then you may do so by using the <code class=\"language-text\">perPage()</code> chaining tool.</p>\n\n\n\n<pre><code rel=\"Set amount of posts per page\" class=\"language-javascript\">\nconst posts = await wp.posts().perPage(20).get();\n</code></pre>\n\n\n\n<p>And that&#8217;s how you fetch posts from WordPress with JavaScript!</p>\n",
    },
    "excerpt": {
      "rendered": "<p>Use the module wpapi to return all posts or a specific number from WordPress rest API v2.</p>\n",
    },
    "author": 1,
    "featured_media": 3118,
    "comment_status": "open",
    "ping_status": "open",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": [],
    "categories": [
        2
    ],
    "tags": [],
    "better_featured_image": {
      // ... better featured imags response
    }
  },

  // ... many more posts
]

And that’s how you fetch posts from WordPress with JavaScript!

Oh wow, you’ve made it this far! If you enjoyed this article perhaps like or retweet the thread on Twitter:

I like to tweet about JavaScript and post helpful code snippets. Follow me there if you would like some too!