Display Posts with WP REST API

Display WordPress Posts on Another Site with WP REST API


Have a WordPress site and want to include your posts on an external site? In this tutorial, I will show you how to use the WordPress REST API to display your posts on a static site with just HTML, CSS, and Javascript.

There are several scenarios where this might be useful but here are the two directly applicable to this tutorial:

  • You want to display a feed of posts on static web hosting (e.g., GitHub Pages, AWS S3, etc.) for your professional web presence
  • You want to use posts from a particular author, category, or tag for separate site(s)[box type=”info”]Skill Level: Beginner[/box]

Getting Started

Update 3/31/17: If you are using WP 4.7 or above you can skip to step 3. The WP REST API is now part of core. No need for a plugin.

  1. Login to your WordPress site and add the WP REST API V2 plugin
  2. Activate the plugin
    Activate WP REST API Plugin
  3. Find your route and define any endpoints. For our purposes, we’re going to retrieve all posts so we will use

    For example, to get all posts for this site, I will use


    Go ahead and copy and paste that URL into your browser. You’ll get a bunch of JSON data. That’s exactly what we want.

    Note that you can narrow down your results by adding to the route. Quick terminology refresher:

    Base path of API: http://example.com/wp-json/
    Route: wp/v2/posts

    For example, we can grab just one post with the ID 2985 like this


    Or, if we want to get posts with tag ID 139


    For the full reference you can see the WP REST API documentation for posts

  4. Test the route in your browser. If you get post data, then we can move to the next step.Note: Only public posts will display. You can also display private posts but this is more complex and we won’t deal with private posts in this tutorial.

Get the Sample Files

I’ve added some files to get you started that allow you to simply paste the route you identified above and display posts.

  1. Clone or download the tutorial files located herehttps://github.com/nathanegraham/wp-rest-api-post-getter

    For those using the GitHub client you will click Open in Desktop. For those who do not use GitHub, just click Download Zip and then extract/unzip the filesGitHub repo download

  2. Open script.js in your favorite editor (Brackets is pretty great)
  3. In Line 2, change the route to the one you identified in the Getting Started section above
  4. Hit Save
  5. Now open index.html in your browser

Putting It All Together

Now that you have your JSON post data and you have the files to display this data on a webpage, you can add it to your site.

  1. Upload the Javascript files to your site’s directory.
    If you don’t have static web hosting I would recommend using AWS S3 or GitHub Pages. Both are free and easy to set up. I won’t go into the details but you can find instructions for AWS S3 site hosting here and GitHub Pages hosting here.
  2. Open index.html and copy everything between the <body> tags
  3. Paste that HTML wherever you would like inside your webpage
  4. Now you will need to tweak the styles and formatting to match the rest of your existing site.For an example of a modified version of of the HTML in this tutorial, see my sitehttp://nathanegraham.github.io/

    Notice that I have removed the image thumbnail and the excerpt. I’ve also moved the date before the post title.


47 responses to “Display WordPress Posts on Another Site with WP REST API”

  1. Hi Nathan, great article! How did you achieve displaying the post’s date in human readable format instead of yyyy-mm-ddThh:ii:ssZ?

    1. Hi Ginnie, Thanks! To parse the date I used something like the below, which you can find in the script.js file here:


      Does that answer your question?

      Note that I have my time and date format set like this:

      Time and Date settings

      Vue.filter('formatDate', function (date_str) {
      var year = date_str.substr(0,4),
      month = parseInt(date_str.substr(5,2)),
      day = date_str.substr(8,2),
      months = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
      return months[month] + " " + day + ", "+year;

  2. Great article! I need to use {{item.featured_media}} for displaying the post thumbnail, but am only getting back the image id. I know I need to add and change parameters to vue.directive to make this work, but am not sure of the syntax to do so. Any advice? Thanks.

    1. Never mind, I figured this out. I am intending to use this for a slider and bring WordPress feeds into our University Drupal site. Thank you again for this code, and I will give kudos and credit of course. My code in progress: http://eres.geneseo.edu/test-api/index-eres.html

      1. Very interesting. Looks like you’re off to a great start. So you’re looking to turn the featured image into a full width slider background and overlay the post title, date, and excerpt? Glad you found this helpful. I’ll definitely link to your version as another example when you’re done.

        1. Greetings Nathan: So far I have the API feed working on our campus video displays. https://www.geneseo.edu/sites/default/files/sites/library/staff-photos/leah-info/milne-entrance-display-700px.png

          A huge challenge is Drupal. No matter how I load the scripts, Drupal ignores the vue js and doesn’t render the feed. The feed renders fine on regular html and also in the video display. I have seen forum posts about similar issues with Drupal. I will keep you updated if I figure this out.

          1. Figured it out 🙂 https://www.geneseo.edu/library

            My college IT department had to grant me special editing permissions (JS/CSS) for our Drupal page. Glad it was nothing more complex than that! I am working on building a slider or rotator script, or styling the feed so there would be one large image and excerpt, followed by thumbnail and excerpts of the next 4-5 posts.

            Thank you so much!

          2. Hi Leah,
            Very Nice! Any chance you can jot down your process here for folks who are using this with Drupal? This is timely because I’m going to be doing something similar on a homepage on a Drupal-based site next month.

  3. Absolutely, Nathan. Do you have a preferred or additional method for communicatiing, ie Slack, GoToMeeting, Twitter ‘old fashioned’ email, etc? I apologize – I did not receive notification of a reply on this forum. I don’t want to miss anything.

    I can start documenting my process here . I am trying to figure out how to pull in tags from the feed and styling a post based on its tag. I may have more questions for you too.

    1. Hi Leah, for sure – feel free to email me at nathan@digitalborn.org. I’d love to hear about the progress on this drupal implementation.

  4. hifall Avatar

    Great post.

    I am trying to figure out how to use WP REST API to update a post under one of the sites in the network. Although I am using the correct credentials, I always get “Sorry, you are not allowed to edit this post.”. Do you have any idea why?


    1. Thanks! This is a good next post that I need to write. In this tutorial I’m just covering displaying posts on another site. Updating posts is a different matter. Can you describe your situation a bit more? You have a WP multisite network and you want a form on a child site to update a post on another child site on your network?

  5. Nice post. Got things working but having issues with html characters being escaped in post titles. For example a post title containing ‘ shows up as ‘

    Have you encountered this before?

    1. Thanks, Oli. Can you share a link to your code and I can take a look? I escape the characters in the script but maybe there’s some conflict.

  6. Murtaza Avatar

    Hello Nathan
    Thank you for great tutorial I can now pull posts from another my website there are total 3500 posts is there is any way I can show 5 or 10 posts per page and add Number pagination to load next page Please see attached Screenshot.

    I understand we can add parameters to url like this


    but if you can guide me how i can add pagination that would be great help.

    Thank you.

    1. Hi Murtaza,
      This is an excellent suggestion. I’ll give it a try this weekend. In the meantime, if you’ve made any progress, can you share?

  7. I am able to get my post info when I put my endpoint into the browser but when I put it into your script.js and open the index.html I am getting a blank page. Am I missing something?

    1. It works for me still. You can take a look at the example I have up on github (linked in the article). Can you provide a link to your blank page?

      1. M Lovett Avatar
        M Lovett

        Here’s the link – Thanks for your help.


        1. Take a look at console by opening your page in Chrome -> right click -> select Inspect -> click Console. I see a couple issues that are likely causing your problem.

          For example, if I go here, there’s no route


          And the reason is because you have an extra “/posts” in there.

          1. Hi, This may be a duplicate but – I did see what you are talking about. I am copying the script.js below – thanks for your help.

            var endpoint = “http://yesterdaysisland.com/wp-json/wp/v2/posts”,
            itemsPerPage = 3,

            Vue.directive(‘thumb’, function (val) {

            if(!val) return;
            var el = this.el;

            Vue.http.jsonp(endpoint+”/media”, {include:val},{jsonp: “_jsonp”}).then(function (response) {
            if(!response.data[0]) return;
            el.style.backgroundImage = “url(“+response.data[0].media_details.sizes.thumbnail.source_url+”)”;

            Vue.filter(‘removeMoreLink’, function (value) {
            return value.replace(/.+?/, ”);

            Vue.filter(‘formatDate’, function (date_str) {
            var year = date_str.substr(0,4),
            month = parseInt(date_str.substr(5,2)),
            day = date_str.substr(8,2),
            months = [”, ‘January’, ‘February’, ‘March’, ‘April’, ‘May’, ‘June’, ‘July’, ‘August’, ‘September’, ‘October’, ‘November’, ‘December’];
            return months[month] + ” ” + day + “, “+year;

            Vue.filter(‘more’, function (value, param) {
            return value.slice(0, param);

            vm = new Vue({
            el: ‘#post_feed’,
            data: {
            items: [],
            loading: true,
            showed: itemsPerPage
            this.$http.jsonp(endpoint+”/posts”, {per_page:100},{jsonp: “_jsonp”}).then(function (response) {
            vm.items = response.data;
            vm.loading = false;


  8. Hi Miki,

    This script looks okay on a quick glance. Could be a configuration issue somewhere else. I still see several errors when I visit your site linked above. You can try just removing “/posts” from your var endpoint line and see if that fixes it.

    1. That did not work.

      I am seeing many errors in the vue.resource.min.js file in DreamWeaver such as ‘Missing semicolon’ or ‘expected this and saw that’ etc.

      Is this a server configuration problem?

      1. OK, this is interesting. I just opened the index.html in Dtreaweaver in split screen and it showed the list perfectly including the images.

        Can you point me to what the server issue might be?


        1. OK – it’s working in Safari – not in Firefox. The later may be a caching issue.

          Thanks for your help. Consider this support issue closed – I’ll work on it from here.

          1. Me again – maybe it’s not closed. After checking various computers around the office, it is working everywhere but in Firefox on a Mac. Windows is fine.


  9. LAST TIME! – I have loaded this into the site proper and it is working on all browsers. I will now get out of your hair!!

    Thanks for your help and timely responses.

    1. Hi Miki, Glad to hear it! When I go to https://nantucket.net/getter/index.html I still see a mixed content warning and a couple minor issues. This is getting blocked because some of the content isn’t loaded over https. Sounds like you have it worked out now though. Maybe this is just a test page.

  10. Hi Nathan,
    thank you for your great post! I am experimenting the WP REST API in localhost and I’ve found that special characters (i.e. ‘&’ ) in the titles of the posts are not decoded. Is there a way to decode the titles?

    1. Hi Moreno,
      That’s a great question. It’s discussed a bit here:




      I’ll have to play around with this later during the week and see if any of these options work. Please let me know if you figure it out.

      1. Probably late to the party but I also had this issue and figured I would post my fix for anyone else who visits this page.
        After browsing the links you posted Nathan I added extra curlies around the part in index.html dealing with the title. It then treats the title like raw html.

        instead of

        1. Thanks, Kaya! Very helpful.

  11. Hi Nathan, i have a classifieds website built with wordpress, now i want to create a directory of sellers with the contact details of the users that register on my site and i want them to have their own subdomains. How do you suppose i could do this?

    1. Hi Kareem, this isn’t exactly related to the REST API and I don’t know the specifics to your situation but here’s what I’d do:
      1. Get a wildcard SSL cert for your base domain
      2. Add the WPMU Dev Domain Mapping plugin to your site
      3. Use any number of membership plugins that come with a directory

      Of course, you could use the REST API to do this and it would be a fun project. But it’s not something that can be explained in a comment.

  12. Hi Nathan and thank you for precious post… a little question… its possible to open the post in the same window? (no _blank or _self) but embed the json in the page.

    Sorry for my bad english and thanks in advance…

    1. Hi Luca,
      Can you explain this a bit more? You want the actual post (when clicked) to open in a blank page on the static hosting instead of the WP site?
      For example, your wordpress site is luca.tld and your static hosted site is at luca.github.io. You want the post to open at luca.github.io and not just link out to luca.tld, correct?
      That’s an interesting thought. I’m sure it’s possible and fairly straightforward. I’ll give it a try this weekend. Let me know if you have any progress before then.

      1. Hi Nathan and thanks for your response. I Want to use the script for develop a news hybrid App and i want read the article (extrapolated from wordpress website) inside the app. Now, onclick, open a new page (external link) but i want read the article inside in the same page o a new app page.

        I hope I explained myself…
        My english is bad I know … but I’m italian 🙂

        1. Hi Luca,
          This seems to be what you’re after:

          For each post you’re going to get the slug as part of the post object. For your link to that post you’ll want to use something like this link in post for vue

          Then in your router you would do:

          path: '/posts/:slug',
          component: SinglePost

          Let me know how it goes.

          More info here:

          1. Hi Nathan and thanks for your response… Have a good time!

  13. Shannon Avatar

    I am trying to get my most recent post from http://sefosterauthor.com/blog/ to show on http://sefosterauthor.com/index.html

    I thought I had it all set up correctly however can you take a look at http://sefosterauthor.com/index.html and tell me what I have wrong?

    I placed the files from the post getter into the plugins/rest-api folder on my server should it just be in the plugins folder?

    1. Hi Shannon,
      These files shouldn’t live in your plugins folder. You also no longer need to use the Rest API plugin if you’re at WP 4.7 or above (it comes built into WP now). You’ll want these files from this tutorial (e.g., index.html, script.js) in some publicly accessible location. Your plugins folder should not be accessible (viewable) by people on the web so you will need to put these files somewhere else like at the root of your site (e.g., outside of wp-content).

  14. Brian Mann Avatar
    Brian Mann

    How do I add back in the post thumbnail functionality? Otherwise, this is perfect for what I need!

  15. Hello nathan !
    that’s a brilliant project.
    I would like to specify the post id in the index.html. Is there a way to do that?
    The goal: Create a a similar thing to twitter embed or facebook embed, in order to embed a specific post.
    Thank you

  16. Rudra Avatar

    Hello Nathan. Good Morning. Hope you are doing well.
    Well, I am looking for one solution from past few months and still yet not figuring it out, how to do that.
    My concern is – I am having 2 different websites on WordPress. One is a news site and another is a business site.

    I post the latest news on a daily basis on my news site. Now I want those daily news posts also to be displayed on my business site too as the latest news.
    If you can kindly help me with the steps or any tools/plugin to do that. Then it will be very helpful for me.

  17. Sanjeev Avatar

    Hi Nathan, Thanks for sharing this. is there any api which will give us pre publish data ?

  18. Ferdinand Avatar

    Dear Nathan,

    thank you very much for this piece of code. Unfortunately it doesn’t pull or print any data on screen. I wrote you an e-mail through the contact page here on this website.

    Woud love to learn what I did wrong on my end. I can see the posts by entering the route directly in my browsers adress bar but the content of index.html stays empty no matter what I do.

  19. Hello there Nathan.

    Nice. Actually this is the first time I have had an error free connection to WordPress from an outside page. No strange WordPress errors as I have gotted used to – pretty amazed about that. And that with this pretty old code. And old Vue version. Kudos!

    However with your code, any site audit I run shows a 404 error because the code only shows “item.link” for the post link, and no actual link. Is there some solution to the code being rendered upon script load? Would it be possible to somehow cache it beforehand? How would you go about doing that?

    Thank you –

Leave a Reply

Your email address will not be published. Required fields are marked *