{"id":133,"date":"2021-03-12T05:49:39","date_gmt":"2021-03-12T11:49:39","guid":{"rendered":"https:\/\/developers.wpengine.com\/blog\/?p=133"},"modified":"2024-02-15T13:20:03","modified_gmt":"2024-02-15T19:20:03","slug":"headless-wordpress-vue-nuxt-js","status":"publish","type":"post","link":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/","title":{"rendered":"Headless WordPress With Vue and Nuxt.js"},"content":{"rendered":"\n<p>If you have not already read our post on&nbsp;<a target=\"_blank\" href=\"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/\" rel=\"noreferrer noopener\">Headless WordPress With Next.js<\/a> I encourage you to go through it if you are interested in learning how to create a Headless WordPress site with React Next.js. This post is going to cover a similar topic, but with&nbsp;<a target=\"_blank\" href=\"https:\/\/vuejs.org\/\" rel=\"noreferrer noopener\">Vue&nbsp;<\/a>and&nbsp;<a target=\"_blank\" href=\"https:\/\/nuxtjs.org\/\" rel=\"noreferrer noopener\">Nuxt.js<\/a>&nbsp;instead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Is Nuxt.js?<\/h2>\n\n\n\n<p>Nuxt.js (or simply Nuxt) is a server-side framework for writing frontend applications using Vue. Vue is a frontend framework similar to Angular or React&#8230; kinda. There are plenty of comparison articles on React versus Vue, and most will point out that Vue is more a framework while React is a library. Let&#8217;s not get into that for this post. For this post, we will assume Vue and React offer essentially the same thing for frontend developers and work with their respective Nuxt and Next server counterparts.<\/p>\n\n\n\n<p>You can think of Nuxt as Next but for Vue instead of React. So if you are looking to write a Headless WordPress site and want to use Vue, Nuxt may be an excellent option for you to use as your server-side framework. It supports Server-Side Rendering and Static Site Generation similar to Next and is generally an opinionated framework that helps you build a frontend website. Before we dive into Nuxt let&#8217;s first discuss how to setup WordPress for headless.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up WordPress For Headless<\/h2>\n\n\n\n<p>If you haven&#8217;t already, check out our post about\u00a0<a href=\"https:\/\/wpengine.com\/builders\/how-to-set-up-wordpress-as-a-headless-cms\/\" target=\"_blank\" rel=\"noreferrer noopener\">setting up WordPress for headless<\/a>. For this post, you will need to install and configure the following plugins (outlined in the post linked above):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a target=\"_blank\" href=\"https:\/\/www.wpgraphql.com\/\" rel=\"noreferrer noopener\">WPGraphQL<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/wordpress.org\/plugins\/faustwp\/\" target=\"_blank\" rel=\"noreferrer noopener\">Faust.js<\/a><\/li>\n<\/ol>\n\n\n\n<p>Make sure you follow the instructions in the post for configuring Faust.js. In the Faust.js settings (found in Settings > Faust), set <strong>Front-end site URL<\/strong> to <code>http:\/\/localhost:3000\/<\/code>. This will eventually be the URL that serves where our frontend site.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating The Nuxt Site<\/h2>\n\n\n\n<p>Now that you have your WordPress site hooked up, let&#8217;s dive into creating our Nuxt app. We will be following the <code>create-nuxt-app<\/code>&nbsp;<a target=\"_blank\" href=\"https:\/\/nuxtjs.org\/docs\/2.x\/get-started\/installation\" rel=\"noreferrer noopener\">installation instructions from the Nuxt documentation<\/a>&nbsp;for the most part, with some configuration. You can start by opening a terminal to where you want to create your app and running the following:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>$ npx create-nuxt-app <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">project-name<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>For this project, I will use the name <code>nuxt-headless-wp<\/code>, but you can use whatever name you want. <code>create-nuxt-app<\/code> is going to ask you some configuration questions, such as:<\/p>\n\n\n<pre class=\"wp-block-code language-text\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>create-nuxt-app v3.5.2\n<\/span><\/span><span class='shcb-loc'><span>\u2728  Generating Nuxt.js project in nuxt-headless-wp\n<\/span><\/span><span class='shcb-loc'><span>? Project name: nuxt-headless-wp\n<\/span><\/span><span class='shcb-loc'><span>? Programming language: TypeScript\n<\/span><\/span><span class='shcb-loc'><span>? Package manager: Npm\n<\/span><\/span><span class='shcb-loc'><span>? UI framework: Bootstrap Vue\n<\/span><\/span><span class='shcb-loc'><span>? Nuxt.js modules: (Press <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">space<\/span>&gt;<\/span> to select, <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span>&gt;<\/span> to toggle all, <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">i<\/span>&gt;<\/span> to invert selection)\n<\/span><\/span><span class='shcb-loc'><span>? Linting tools: ESLint, Prettier\n<\/span><\/span><span class='shcb-loc'><span>? Testing framework: Jest\n<\/span><\/span><span class='shcb-loc'><span>? Rendering mode: Universal (SSR \/ SSG)\n<\/span><\/span><span class='shcb-loc'><span>? Deployment target: Server (Node.js hosting)\n<\/span><\/span><span class='shcb-loc'><span>? Development tools: (Press <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">space<\/span>&gt;<\/span> to select, <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span>&gt;<\/span> to toggle all, <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">i<\/span>&gt;<\/span> to invert selection)\n<\/span><\/span><span class='shcb-loc'><span>? Continuous integration: None\n<\/span><\/span><span class='shcb-loc'><span>? Version control system: Git\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>After your Nuxt app is generated you will get instructions on how to run your site, which should look something like the following:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>$ cd nuxt-headless-wp\n<\/span><\/span><span class='shcb-loc'><span>$ npm run dev\n<\/span><\/span><\/code><\/span><\/pre>\n\n\n<p>If you don&#8217;t get any errors, your site should be running on <a rel=\"noreferrer noopener\" href=\"http:\/\/localhost:3000\/\" target=\"_blank\">http:\/\/localhost:3000\/<\/a>. We&#8217;re done&#8230; <\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Not! Now is when things get interesting.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building Pages For The Blog<\/h3>\n\n\n\n<p>We&#8217;re going to keep with a simple UI using only Bootstrap CSS classes. Let&#8217;s first scaffold out our HTML with some dummy data and style it a little before adding in data from our WordPress CMS. We will want the index page to show a list of posts and let you navigate to an individual post. Let&#8217;s start with the index page.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Showing A List Of Posts<\/h4>\n\n\n\n<p>In <code>pages\/index.vue<\/code>, remove all of the styles in the <code>&lt;style&gt;&lt;\/style&gt;<\/code> tags. We won&#8217;t be needing this. Next, let&#8217;s add some dummy data in the TS area of our <code>index.vue<\/code>. Add the following <code>script<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Vue <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vue'<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Vue.extend({\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">computed<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>    posts() {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> &#91;\n<\/span><\/span><span class='shcb-loc'><span>        {\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">'Test Post'<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">slug<\/span>: <span class=\"hljs-string\">'test-post'<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">content<\/span>: <span class=\"hljs-string\">'&lt;p&gt;This is a test post&lt;\/p&gt;'<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-attr\">excerpt<\/span>: <span class=\"hljs-string\">'&lt;p&gt;This is a test post&lt;\/p&gt;'<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        },\n<\/span><\/span><span class='shcb-loc'><span>      ]\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>    pageInfo() {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">endCursor<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">hasNextPage<\/span>: <span class=\"hljs-literal\">false<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">hasPreviousPage<\/span>: <span class=\"hljs-literal\">false<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">startCursor<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      }\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>})\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The code above sets up two computed properties with default values for a list of posts and page information. We are using computed properties because later, we will populate these with values from a Vuex store.<\/p>\n\n\n\n<p>Now that we have some sample data let&#8217;s build out our list of posts. Use the following template:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-center\"<\/span>&gt;<\/span>Nuxt Headless WordPress Demo<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container py-4 posts\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"row\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">post-card<\/span> <span class=\"hljs-attr\">v-for<\/span>=<span class=\"hljs-string\">\"post in posts\"<\/span> <span class=\"hljs-attr\">:key<\/span>=<span class=\"hljs-string\">\"post.slug\"<\/span> <span class=\"hljs-attr\">:post<\/span>=<span class=\"hljs-string\">\"post\"<\/span> \/&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"d-flex w-100\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"ml-auto\"<\/span> <span class=\"hljs-attr\">v-if<\/span>=<span class=\"hljs-string\">\"pageInfo.hasNextPage\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NuxtLink<\/span> <span class=\"hljs-attr\">:to<\/span>=<span class=\"hljs-string\">\"{ query: { after: pageInfo.endCursor } }\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">                &gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Next Page<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">NuxtLink<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">              &gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\">            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This code is going to iterate through our <code>posts<\/code> computed property and render a <code>post-card<\/code> for each post. It will also show a link to view the next page of posts if there is one. You might be wondering what <code>post-card<\/code> is. We need to create our <code>post-card<\/code> component so that we can show our posts as cards. Add a <code>components\/PostCard.vue<\/code> and put the following code in it:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"col-12 py-5\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"card shadow\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"card-body\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h5<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"card-title\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NuxtLink<\/span> <span class=\"hljs-attr\">:to<\/span>=<span class=\"hljs-string\">\"{ name: 'slug', params: { slug: post.slug } }\"<\/span>&gt;<\/span>{{\n<\/span><\/span><span class='shcb-loc'><span>            post.title\n<\/span><\/span><span class='shcb-loc'><span>          }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">NuxtLink<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h5<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-comment\">&lt;!-- eslint-disable-next-line vue\/no-v-html --&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"card-text\"<\/span> <span class=\"hljs-attr\">v-html<\/span>=<span class=\"hljs-string\">\"post.excerpt\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\"><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">import<\/span> { PropsDefinition } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vue\/types\/options'<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">import<\/span> { Post } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'~\/store\/posts'<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">  <span class=\"hljs-attr\">props<\/span>: &#91;<span class=\"hljs-string\">'post'<\/span>] <span class=\"hljs-keyword\">as<\/span> PropsDefinition&lt;{ <span class=\"hljs-attr\">post<\/span>: Post }&gt;,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">}<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>PostCard<\/code> component expects a <code>post<\/code> prop and will render the post title and excerpt in a Bootstrap card. It will also link to what will eventually be our single post page. Before you continue, run your app and make sure you see the test post.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Showing A Single Post<\/h4>\n\n\n\n<p>Now that we have our list of posts displaying let&#8217;s add a single post page. If you look at the <code>PostCard.vue<\/code> component, you will see that we link to a <code>slug<\/code> page that takes in a <code>slug<\/code> parameter. Create a <code>pages\/_slug.vue<\/code> that will receive the slug URL parameter and use it to display a post. Put the following code into the <code>_slug.vue<\/code> page:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-center\"<\/span>&gt;<\/span>{{ post.title }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">&lt;!-- eslint-disable-next-line vue\/no-v-html --&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"py-5\"<\/span> <span class=\"hljs-attr\">v-html<\/span>=<span class=\"hljs-string\">\"post.content\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\"><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">import<\/span> Vue <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vue'<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Vue.extend({<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">  <span class=\"hljs-attr\">computed<\/span>: {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">    post() {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">      <span class=\"hljs-keyword\">return<\/span> {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">        <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">'Test Post'<\/span>,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">        <span class=\"hljs-attr\">slug<\/span>: <span class=\"hljs-string\">'test-post'<\/span>,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">        <span class=\"hljs-attr\">content<\/span>: <span class=\"hljs-string\">'&lt;p&gt;This is a test post&lt;\/p&gt;'<\/span>,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">        <span class=\"hljs-attr\">excerpt<\/span>: <span class=\"hljs-string\">'&lt;p&gt;This is a test post&lt;\/p&gt;'<\/span>,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">      }<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">    },<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">  },<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">})<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>When you run your app, you will be able to navigate from the list of posts to a single post. Now we have to actually populate our list of posts with data from our WordPress site. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building The Posts Store<\/h3>\n\n\n\n<p>To get data from WordPress, we need a store, but we need to install some dependencies. Run the following commands from the root directory of your project:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>$ npm i apollo-boost graphql isomorphic-fetch vue-apollo\n<\/span><\/span><span class='shcb-loc'><span>$ npm i -D @types\/isomorphic-fetch\n<\/span><\/span><\/code><\/span><\/pre>\n\n\n<p>This will install the dependencies we need to call our WordPress GraphQL API and retrieve our lists of posts and individual posts. The next thing we need to do is set up a store for our posts. Add a <code>store\/posts.ts<\/code> file. This file is going to have a number of things:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>TypeScript interfaces for our data<\/li>\n\n\n\n<li>GQL query strings<\/li>\n\n\n\n<li>Apollo client setup<\/li>\n\n\n\n<li>State definition<\/li>\n\n\n\n<li>Mutation methods<\/li>\n\n\n\n<li>Action methods<\/li>\n<\/ol>\n\n\n\n<p>Let&#8217;s step through this 1-by-1. We&#8217;re going to need to import the following dependencies at the top of our <code>posts.ts<\/code> file:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { ActionContext } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vuex'<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> ApolloClient, { gql } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'apollo-boost'<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> fetch <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'isomorphic-fetch'<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Next, let&#8217;s create our TypeScript interfaces, so we know the shape of the data we&#8217;re trying to fetch. In your <code>posts.ts<\/code> file put the following interfaces:<\/p>\n\n\n<pre class=\"wp-block-code language-ts\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-selector-tag\">export<\/span> <span class=\"hljs-selector-tag\">interface<\/span> <span class=\"hljs-selector-tag\">Post<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">id<\/span>: string\n<\/span><\/span><span class='shcb-loc'><span>  slug: string\n<\/span><\/span><span class='shcb-loc'><span>  title: string\n<\/span><\/span><span class='shcb-loc'><span>  content: string\n<\/span><\/span><span class='shcb-loc'><span>  excerpt: string\n<\/span><\/span><span class='shcb-loc'><span>  uri: string\n<\/span><\/span><span class='shcb-loc'><span>  status: string\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-selector-tag\">export<\/span> <span class=\"hljs-selector-tag\">interface<\/span> <span class=\"hljs-selector-tag\">PageInfo<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">endCursor<\/span>: string\n<\/span><\/span><span class='shcb-loc'><span>  hasNextPage: boolean\n<\/span><\/span><span class='shcb-loc'><span>  hasPreviousPage: boolean\n<\/span><\/span><span class='shcb-loc'><span>  startCursor: string\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-selector-tag\">export<\/span> <span class=\"hljs-selector-tag\">interface<\/span> <span class=\"hljs-selector-tag\">PostsState<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">nodes<\/span>: Post&#91;]\n<\/span><\/span><span class='shcb-loc'><span>  pageInfo: PageInfo\n<\/span><\/span><span class='shcb-loc'><span>  post: Post\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, let&#8217;s use the <code>gql<\/code> library to format our GQL queries. Earlier, we installed the WPGraphQL plugin for WordPress, so we need to use its schema. Put the following queries in your <code>posts.ts<\/code> file:<\/p>\n\n\n<pre class=\"wp-block-code language-ts\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> postsQuery = gql`\n<\/span><\/span><span class='shcb-loc'><span>  fragment pageInfoData on WPPageInfo {\n<\/span><\/span><span class='shcb-loc'><span>    endCursor\n<\/span><\/span><span class='shcb-loc'><span>    hasNextPage\n<\/span><\/span><span class='shcb-loc'><span>    hasPreviousPage\n<\/span><\/span><span class='shcb-loc'><span>    startCursor\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>  fragment listPostData on Post {\n<\/span><\/span><span class='shcb-loc'><span>    id\n<\/span><\/span><span class='shcb-loc'><span>    slug\n<\/span><\/span><span class='shcb-loc'><span>    title\n<\/span><\/span><span class='shcb-loc'><span>    content\n<\/span><\/span><span class='shcb-loc'><span>    excerpt\n<\/span><\/span><span class='shcb-loc'><span>    uri\n<\/span><\/span><span class='shcb-loc'><span>    status\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>  query GetPosts(\n<\/span><\/span><span class='shcb-loc'><span>    $where: RootQueryToPostConnectionWhereArgs\n<\/span><\/span><span class='shcb-loc'><span>    $after: String\n<\/span><\/span><span class='shcb-loc'><span>    $before: String\n<\/span><\/span><span class='shcb-loc'><span>    $first: Int\n<\/span><\/span><span class='shcb-loc'><span>    $last: Int\n<\/span><\/span><span class='shcb-loc'><span>  ) {\n<\/span><\/span><span class='shcb-loc'><span>    posts(\n<\/span><\/span><span class='shcb-loc'><span>      where: $where\n<\/span><\/span><span class='shcb-loc'><span>      after: $after\n<\/span><\/span><span class='shcb-loc'><span>      before: $before\n<\/span><\/span><span class='shcb-loc'><span>      first: $first\n<\/span><\/span><span class='shcb-loc'><span>      last: $last\n<\/span><\/span><span class='shcb-loc'><span>    ) {\n<\/span><\/span><span class='shcb-loc'><span>      pageInfo {\n<\/span><\/span><span class='shcb-loc'><span>        ...pageInfoData\n<\/span><\/span><span class='shcb-loc'><span>      }\n<\/span><\/span><span class='shcb-loc'><span>      nodes {\n<\/span><\/span><span class='shcb-loc'><span>        ...listPostData\n<\/span><\/span><span class='shcb-loc'><span>      }\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>`\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> postQuery = gql`\n<\/span><\/span><span class='shcb-loc'><span>  fragment postData on Post {\n<\/span><\/span><span class='shcb-loc'><span>    id\n<\/span><\/span><span class='shcb-loc'><span>    slug\n<\/span><\/span><span class='shcb-loc'><span>    title\n<\/span><\/span><span class='shcb-loc'><span>    content\n<\/span><\/span><span class='shcb-loc'><span>    uri\n<\/span><\/span><span class='shcb-loc'><span>    status\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>  fragment pageData on Page {\n<\/span><\/span><span class='shcb-loc'><span>    id\n<\/span><\/span><span class='shcb-loc'><span>    slug\n<\/span><\/span><span class='shcb-loc'><span>    title\n<\/span><\/span><span class='shcb-loc'><span>    content\n<\/span><\/span><span class='shcb-loc'><span>    uri\n<\/span><\/span><span class='shcb-loc'><span>    status\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>  query GetContentNode($id: ID!) {\n<\/span><\/span><span class='shcb-loc'><span>    contentNode(id: $id, idType: URI) {\n<\/span><\/span><span class='shcb-loc'><span>      ... on Post {\n<\/span><\/span><span class='shcb-loc'><span>        ...postData\n<\/span><\/span><span class='shcb-loc'><span>      }\n<\/span><\/span><span class='shcb-loc'><span>      ... on Page {\n<\/span><\/span><span class='shcb-loc'><span>        ...pageData\n<\/span><\/span><span class='shcb-loc'><span>      }\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>`\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Use the first query to get a list of posts and the second an individual post. Note that the fields in our query match the fields in the TypeScript interfaces.<\/p>\n\n\n\n<p>Next, let&#8217;s set up our Apollo client. I am going to use a demo WordPress site, but you can use your own:<\/p>\n\n\n<pre class=\"wp-block-code language-ts\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> client = <span class=\"hljs-keyword\">new<\/span> ApolloClient({\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">uri<\/span>: <span class=\"hljs-string\">`https:\/\/headlessfw.wpengine.com\/graphql`<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>  fetch,\n<\/span><\/span><span class='shcb-loc'><span>})\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now we need to define our <code>state<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code language-ts\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">state<\/span>(<span class=\"hljs-params\"><\/span>): <span class=\"hljs-title\">PostsState<\/span> <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">nodes<\/span>: &#91;],\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">pageInfo<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">endCursor<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">hasNextPage<\/span>: <span class=\"hljs-literal\">false<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">hasPreviousPage<\/span>: <span class=\"hljs-literal\">false<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">startCursor<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">post<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">slug<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">content<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">excerpt<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">uri<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">status<\/span>: <span class=\"hljs-string\">''<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The last piece of this puzzle is to create the functions that will fetch our data and provide it to the view. Create the following mutations:<\/p>\n\n\n<pre class=\"wp-block-code language-ts\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> mutations = {\n<\/span><\/span><span class='shcb-loc'><span>  setPosts(state: PostsState, <span class=\"hljs-attr\">posts<\/span>: any&#91;]) {\n<\/span><\/span><span class='shcb-loc'><span>    state.nodes = posts\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>  setPost(state: PostsState, <span class=\"hljs-attr\">post<\/span>: any) {\n<\/span><\/span><span class='shcb-loc'><span>    state.post = post\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>  setPageInfo(state: PostsState, <span class=\"hljs-attr\">pageInfo<\/span>: any) {\n<\/span><\/span><span class='shcb-loc'><span>    state.pageInfo = pageInfo\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>These mutations will let us set a state and provide a list of posts, page information, and an individual post. Next, create the following actions:<\/p>\n\n\n<pre class=\"wp-block-code language-ts\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> actions = {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">async<\/span> getPosts(\n<\/span><\/span><span class='shcb-loc'><span>    { commit }: ActionContext&lt;PostsState, PostsState&gt;,\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">variables<\/span>: any\n<\/span><\/span><span class='shcb-loc'><span>  ) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> client.query({\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">query<\/span>: postsQuery,\n<\/span><\/span><span class='shcb-loc'><span>      variables,\n<\/span><\/span><span class='shcb-loc'><span>    })\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> { nodes, pageInfo } = result.data?.posts\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    commit(<span class=\"hljs-string\">'setPosts'<\/span>, nodes)\n<\/span><\/span><span class='shcb-loc'><span>    commit(<span class=\"hljs-string\">'setPageInfo'<\/span>, pageInfo)\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">async<\/span> getPost(\n<\/span><\/span><span class='shcb-loc'><span>    { commit }: ActionContext&lt;PostsState, PostsState&gt;,\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">slug<\/span>: string\n<\/span><\/span><span class='shcb-loc'><span>  ) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> client.query({\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">query<\/span>: postQuery,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">variables<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">id<\/span>: slug,\n<\/span><\/span><span class='shcb-loc'><span>      },\n<\/span><\/span><span class='shcb-loc'><span>    })\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> post = result.data?.contentNode\n<\/span><\/span><span class='shcb-loc'><span>    commit(<span class=\"hljs-string\">'setPost'<\/span>, post)\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We have two actions: getting the list of posts and the other for getting an individual post. Both use our GQL queries and the Apollo client to make requests to our WordPress site for data, and then they commit the data to the state by calling the mutations. Now we have our store, the last piece we need is to wire it up to our views.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wiring Up The Data<\/h3>\n\n\n\n<p>To wire up the state from our store to our view, we will need to modify our <code>index.vue<\/code> and <code>_slug.vue<\/code> pages. Modify the <code>script<\/code> in the <code>index.vue<\/code> page to look like the following:<\/p>\n\n\n<pre class=\"wp-block-code language-ts\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Vue <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vue'<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { PostsState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'~\/store\/posts'<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> pageCount = <span class=\"hljs-number\">5<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Vue.extend({\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">computed<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>    posts() {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> (<span class=\"hljs-keyword\">this<\/span>.$store.state.posts <span class=\"hljs-keyword\">as<\/span> PostsState).nodes\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>    pageInfo() {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> (<span class=\"hljs-keyword\">this<\/span>.$store.state.posts <span class=\"hljs-keyword\">as<\/span> PostsState).pageInfo\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">watch<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">async<\/span> $route() {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">this<\/span>.$nuxt.refresh()\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-built_in\">window<\/span>.scrollTo(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>)\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">async<\/span> asyncData({ store, query }) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">await<\/span> store.dispatch(<span class=\"hljs-string\">'posts\/getPosts'<\/span>, {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">after<\/span>: query.after,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">before<\/span>: query.before,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">first<\/span>: query.before ? <span class=\"hljs-literal\">undefined<\/span> : pageCount,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">last<\/span>: query.before ? pageCount : <span class=\"hljs-literal\">undefined<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>    })\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>})\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This accomplishes a few goals. First, it changes our computed properties from being hardcoded to using the <code>posts<\/code> state values. Second, it sets up a <code>$route<\/code> watcher that will refresh our data when the route changes and scroll to the top of the page. This is used for pagination (note we are using a pageCount of 10). The next page will create a query string with the appropriate parameters and refresh the data when you go to the next page. The last thing this code does is implement the asyncData hook to dispatch the <code>posts\/getPosts<\/code> action, retrieve the list of posts, and then set them on the state. Now let&#8217;s modify the <code>_slug.vue<\/code> to have the following <code>script<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Vue <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'vue'<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Vue.extend({\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">computed<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>    post() {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">this<\/span>.$store.state.posts.post\n<\/span><\/span><span class='shcb-loc'><span>    },\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">async<\/span> asyncData({ store, params }) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">await<\/span> store.dispatch(<span class=\"hljs-string\">'posts\/getPost'<\/span>, params.slug)\n<\/span><\/span><span class='shcb-loc'><span>  },\n<\/span><\/span><span class='shcb-loc'><span>})\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This is much more straightforward. All we need to do in the <code>_slug.vue<\/code> page is dispatch the action to get a single post.<\/p>\n\n\n\n<p>There you have it; you have successfully set up a Headless WordPress blog using Vue and Nuxt! Now when you run your site, you should see a paginated list of posts. If you have more than 10 posts, you will be able to page through them. Click on the title of a post, that title will take you to the individual page for that post, where you see all of the content.<\/p>\n\n\n\n<p>When you are still struggling to get your site setup, <a data-type=\"URL\" data-id=\"https:\/\/github.com\/wjohnsto\/nuxt-headless-wp\" rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/wjohnsto\/nuxt-headless-wp\" target=\"_blank\">check out the code for this post<\/a>. If you haven&#8217;t already and are interested, be sure to check out our post on <a data-type=\"post\" data-id=\"20\" rel=\"noreferrer noopener\" href=\"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/\" target=\"_blank\">Headless WordPress Using NextJS<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you have not already read our post on&nbsp;Headless WordPress With Next.js I encourage you to go through it if you are interested in learning how to create a Headless [&hellip;]<\/p>\n","protected":false},"author":22,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"footnotes":""},"categories":[23],"tags":[],"class_list":["post-133","post","type-post","status-publish","format-standard","hentry","category-headless"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Headless WordPress With Vue and Nuxt.js - Builders<\/title>\n<meta name=\"description\" content=\"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Headless WordPress With Vue and Nuxt.js\" \/>\n<meta property=\"og:description\" content=\"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/\" \/>\n<meta property=\"og:site_name\" content=\"Builders\" \/>\n<meta property=\"article:published_time\" content=\"2021-03-12T11:49:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-15T19:20:03+00:00\" \/>\n<meta name=\"author\" content=\"Will Johnston\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Headless WordPress With Vue and Nuxt.js\" \/>\n<meta name=\"twitter:description\" content=\"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.\" \/>\n<meta name=\"twitter:creator\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:site\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Will Johnston\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/\"},\"author\":{\"name\":\"Will Johnston\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/person\\\/12c2a773cdc5451ead7cb8c7f2f1fd83\"},\"headline\":\"Headless WordPress With Vue and Nuxt.js\",\"datePublished\":\"2021-03-12T11:49:39+00:00\",\"dateModified\":\"2024-02-15T19:20:03+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/\"},\"wordCount\":1454,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\"},\"articleSection\":[\"Headless\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/\",\"name\":\"Headless WordPress With Vue and Nuxt.js - Builders\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#website\"},\"datePublished\":\"2021-03-12T11:49:39+00:00\",\"dateModified\":\"2024-02-15T19:20:03+00:00\",\"description\":\"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-vue-nuxt-js\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Headless WordPress With Vue and Nuxt.js\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#website\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\",\"name\":\"Builders\",\"description\":\"Reimagining the way we build with WordPress.\",\"publisher\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\",\"name\":\"WP Engine\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2024\\\/05\\\/WP-Engine-Horizontal@2x.png\",\"contentUrl\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2024\\\/05\\\/WP-Engine-Horizontal@2x.png\",\"width\":348,\"height\":68,\"caption\":\"WP Engine\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/wpebuilders\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCh1WuL54XFb9ZI6m6goFv1g\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/person\\\/12c2a773cdc5451ead7cb8c7f2f1fd83\",\"name\":\"Will Johnston\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g\",\"caption\":\"Will Johnston\"},\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/author\\\/wjohnsto\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Headless WordPress With Vue and Nuxt.js - Builders","description":"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/","og_locale":"en_US","og_type":"article","og_title":"Headless WordPress With Vue and Nuxt.js","og_description":"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.","og_url":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/","og_site_name":"Builders","article_published_time":"2021-03-12T11:49:39+00:00","article_modified_time":"2024-02-15T19:20:03+00:00","author":"Will Johnston","twitter_card":"summary_large_image","twitter_title":"Headless WordPress With Vue and Nuxt.js","twitter_description":"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.","twitter_creator":"@wpebuilders","twitter_site":"@wpebuilders","twitter_misc":{"Written by":"Will Johnston","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/#article","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/"},"author":{"name":"Will Johnston","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/12c2a773cdc5451ead7cb8c7f2f1fd83"},"headline":"Headless WordPress With Vue and Nuxt.js","datePublished":"2021-03-12T11:49:39+00:00","dateModified":"2024-02-15T19:20:03+00:00","mainEntityOfPage":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/"},"wordCount":1454,"commentCount":0,"publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"articleSection":["Headless"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/","url":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/","name":"Headless WordPress With Vue and Nuxt.js - Builders","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/#website"},"datePublished":"2021-03-12T11:49:39+00:00","dateModified":"2024-02-15T19:20:03+00:00","description":"Setup a Headless WordPress site with a Nuxt.js and Vue frontend! This guide will help you create a headless blog using WordPress as your CMS.","breadcrumb":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-vue-nuxt-js\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wpengine.com\/builders\/"},{"@type":"ListItem","position":2,"name":"Headless WordPress With Vue and Nuxt.js"}]},{"@type":"WebSite","@id":"https:\/\/wpengine.com\/builders\/#website","url":"https:\/\/wpengine.com\/builders\/","name":"Builders","description":"Reimagining the way we build with WordPress.","publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wpengine.com\/builders\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/wpengine.com\/builders\/#organization","name":"WP Engine","url":"https:\/\/wpengine.com\/builders\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/","url":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","contentUrl":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","width":348,"height":68,"caption":"WP Engine"},"image":{"@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/wpebuilders","https:\/\/www.youtube.com\/channel\/UCh1WuL54XFb9ZI6m6goFv1g"]},{"@type":"Person","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/12c2a773cdc5451ead7cb8c7f2f1fd83","name":"Will Johnston","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g","caption":"Will Johnston"},"url":"https:\/\/wpengine.com\/builders\/author\/wjohnsto\/"}]}},"_links":{"self":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/comments?post=133"}],"version-history":[{"count":0,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/133\/revisions"}],"wp:attachment":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/media?parent=133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/categories?post=133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/tags?post=133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}