{"id":5237,"date":"2023-05-26T10:05:48","date_gmt":"2023-05-26T16:05:48","guid":{"rendered":"https:\/\/wpengine.com\/builders\/?p=5237"},"modified":"2023-12-20T07:39:43","modified_gmt":"2023-12-20T13:39:43","slug":"headless-wordpress-nuxt-3-vue-3","status":"publish","type":"post","link":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/","title":{"rendered":"Headless WordPress with Nuxt 3 &#038; Vue 3"},"content":{"rendered":"\n<p>In this article, you\u2019ll learn how to build a basic headless WordPress site using Nuxt 3 and Vue 3. <a href=\"https:\/\/nuxt.com\/\">Nuxt 3<\/a> is a full-stack framework built around the latest version of the <a href=\"https:\/\/vuejs.org\/guide\/introduction.html\">Vue JavaScript framework<\/a>. Nuxt 3 comes built-in with lots of features that developers will enjoy, including auto-imports, abstractions for data fetching, and support for multiple deployment targets. It uses Vue 3 for the frontend layer and a server rendering engine called Nitro, which is open source and can be used for other projects.&nbsp;<\/p>\n\n\n\n<p>Hopefully, this article will help you get started using Nuxt 3 and headless WordPress! You\u2019ll be creating an app from scratch. If you need some additional information to migrate from Nuxt 2 to Nuxt 3, check out <a href=\"https:\/\/nuxt.com\/docs\/migration\/overview\">this migration guide<\/a>. You can access <a href=\"https:\/\/github.com\/JEverhart383\/nuxt-wordpress-starter\">the finished project<\/a> for this tutorial on GitHub.<\/p>\n\n\n\n<p>In this tutorial, you will do the following things:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Start a Nuxt 3 project from scratch and install Tailwind CSS and Nuxt DevTools<\/li>\n\n\n\n<li>Create static and dynamic routes in Nuxt 3<\/li>\n\n\n\n<li>Use data fetching abstractions in Nuxt 3 to query and transform data from WPGraphQL<\/li>\n\n\n\n<li>Build and deploy your Nuxt application to a Node.js server environment<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Installing Nuxt<\/h2>\n\n\n\n<p>To get started with Nuxt 3, open up your terminal application and run the following command:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>npx nuxi@latest init nuxt-wordpress\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\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>After Nuxt 3 has finished installing, change your directory to your new Nuxt 3 project. Once inside your project\u2019s directory, run <code>npm run install<\/code> and then <code>npm run dev<\/code> to start the server in development mode.<\/p>\n\n\n\n<p>Once the development server starts up, you should be able to load <code>http:\/\/localhost:3000\/<\/code> in your browser and see the following start screen provided by the Nuxt application.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"711\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-3-starter-screen-1024x711.png\" alt=\"A screenshot of the Nuxt application starter screen\" class=\"wp-image-5270\" srcset=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-3-starter-screen-1024x711.png 1024w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-3-starter-screen-300x208.png 300w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-3-starter-screen-768x533.png 768w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-3-starter-screen.png 1394w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Now that you know your Nuxt project is running, let&#8217;s install a few Nuxt 3 modules to get us started. First, you can install the experimental <a href=\"https:\/\/devtools.nuxtjs.org\/\">Nuxt <code>DevTools<\/code><\/a> as a dev dependency to help you develop your applications more easily. Then you can install the Nuxt Tailwind CSS module so you can use those styles in your app.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>npm install @nuxt\/devtools -d\n<\/span><\/span><span class='shcb-loc'><span>npm install @nuxtjs\/tailwindcss --save\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\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With both of those packages installed, you will need to add them as modules to your <code>nuxt.config.ts<\/code> file in the root of your project:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-comment\">\/\/ https:\/\/nuxt.com\/docs\/api\/configuration\/nuxt-config<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> defineNuxtConfig({\n<\/span><\/span><span class='shcb-loc'><span>   modules: &#91;\n<\/span><\/span><span class='shcb-loc'><span>       <span class=\"hljs-string\">'@nuxt\/devtools'<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>       <span class=\"hljs-string\">'@nuxtjs\/tailwindcss'<\/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\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Once these entries have been added to your Nuxt config file, restart the development server to view them in the browser. The Nuxt <code>DevTools<\/code> will add a small Nuxt icon to the bottom of the screen that triggers the dev tools modal to open.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"882\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-dev-tools-overview-1024x882.png\" alt=\"A screenshot of the Nuxt DevTools open on the starter screen page\" class=\"wp-image-5271\" srcset=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-dev-tools-overview-1024x882.png 1024w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-dev-tools-overview-300x258.png 300w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-dev-tools-overview-768x661.png 768w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-dev-tools-overview.png 1124w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>The Nuxt <code>DevTools<\/code> have a lot of functionality, allowing you to inspect components and their state, examine the modules you have installed, and even modify your Tailwind config directly from this interface. To get started building out your pages, you can click on the routing menu inside of the <code>DevTools<\/code> to enable routes inside your project.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"883\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/devtools-route-menu-nuxt-1024x883.png\" alt=\"A screenshot of the routing menu on the Nuxt starter screen\" class=\"wp-image-5272\" srcset=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/devtools-route-menu-nuxt-1024x883.png 1024w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/devtools-route-menu-nuxt-300x259.png 300w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/devtools-route-menu-nuxt-768x663.png 768w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/devtools-route-menu-nuxt.png 1122w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>By clicking the button labeled <code>Enable Routing<\/code>, Nuxt will make the necessary changes to your project structure by adding a pages directory to store our routes and modifying the application root in <code>app.vue<\/code> to display your routes instead of this default welcome screen. Once the dev server reloads, you should see a page that looks like this, indicating that your Nuxt application is now serving the routes we define.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"884\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-success-routing-enabled-1024x884.png\" alt=\"A screen shot of the index route in Nuxt after enabling routing\" class=\"wp-image-5273\" srcset=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-success-routing-enabled-1024x884.png 1024w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-success-routing-enabled-300x259.png 300w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-success-routing-enabled-768x663.png 768w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/nuxt-success-routing-enabled.png 1123w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Now that the structure is in place, you can begin creating static and dynamic routes that pull data from your WordPress backend.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding Nuxt Routing<\/h2>\n\n\n\n<p>Although you enabled routing using the <code>DevTools<\/code>, it&#8217;s important that you understand how Nuxt routing works inside your project&#8217;s directory. When you enabled routing, Nuxt made modifications to two different parts of your project. First, it created a <code>pages<\/code> directory where your page-based route files will live. Then, it updated your application root to display those routes based on the current URL.<\/p>\n\n\n\n<p>If you look inside the <code>app.vue<\/code> file, you will see the following code. Nuxt implements its own component called <code>&lt;NuxtPage \/&gt;<\/code> to display the route file that matches the current URL:<\/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>&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\">NuxtPage<\/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><\/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>Inside the <code>pages<\/code> directory, you&#8217;ll see a <code>index.vue<\/code> file that contains both a component <code>template<\/code> and a component <code>script<\/code>. As a part of this project, you will modify this <code>index.vue<\/code> file to display a list of your WordPress posts, but you will also need to create an additional route to display each post\u2019s details.&nbsp;<\/p>\n\n\n\n<p><br>To do that, you will implement a <a href=\"https:\/\/nuxt.com\/docs\/guide\/directory-structure\/pages\/#catch-all-route\">catch-all route in Nuxt<\/a> by creating a file with the following name in the pages directory: <code>[...uri].vue<\/code>. Catch-all routes are useful because they allow you to match complex URI patterns that may exist in your WordPress CMS. Inside your URI template, add some additional markup just to get things working. After you save this file, you should be able to visit any URI in the browser, like <code>\/test<\/code>, and view the contents of this page component.<\/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\">h1<\/span>&gt;<\/span>URI Page<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\">template<\/span>&gt;<\/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<h2 class=\"wp-block-heading\">Building Out Some Basic Components<\/h2>\n\n\n\n<p>For this project, you have two routes that you&#8217;ll need to display: your blog\u2019s index page and your individual blog posts. Now, you can create a few components to add some content to these routes. Inside the root of your project, create a folder called <code>components<\/code> and add a file called <code>TheHeader.vue<\/code>. Since you enabled the Tailwind CSS module, you can use those styles in your component.&nbsp;<\/p>\n\n\n\n<p>Add the following code to your header file:<\/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\">header<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"relative w-full p-6 h-85px mx-auto bg-slate-200\"<\/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\">className<\/span>=<span class=\"hljs-string\">\"text-4xl\"<\/span>&gt;<\/span>Nuxt WP<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\">header<\/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><\/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>Once the component file is created, you can use it in your route files. Nuxt 3 supports auto-imports, so all you have to do is use the component inside of a <code>template<\/code> block, as you see in the example below. While you\u2019re adding this component, you can also create a <code>div<\/code> with some <code>grid<\/code> layout options that will hold your posts once you begin using dynamic data:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" 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\">script<\/span> <span class=\"hljs-attr\">setup<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"actionscript\"><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"actionscript\"><span class=\"hljs-keyword\">const<\/span> route = useRoute();<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"actionscript\"><\/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><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/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\">TheHeader<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TheHeader<\/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\">   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"grid gap-8 grid-cols-1 lg:grid-cols-3 p-6\"<\/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\">div<\/span>&gt;<\/span><\/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\"><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span><\/span><\/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\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/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\">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>Automatic imports are a great feature for developers because it eliminates the need to write as much boilerplate to build your site. After you&#8217;ve added <code>TheHeader<\/code> component to your <code>index<\/code> route, add it to your <code>URI<\/code> route as well.&nbsp;<\/p>\n\n\n\n<p>Now that you have a route file prepared to accept some data, you can shift gears and focus on setting up WordPress as a headless CMS using WPGraphQL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuring WordPress and WPGraphQL<\/h2>\n\n\n\n<p>While there are a ton of ways to work with WordPress locally, with tools like MAMP, XAMPP, Vagrant, and even Docker, the quickest way to spin up a local WordPress site is by using the <a href=\"https:\/\/localwp.com\/\">Local development <\/a>environment.<\/p>\n\n\n\n<p>After downloading the software, you can create a local WordPress site for this project in a few clicks:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2022\/10\/ScreenFlow.gif\" alt=\"A GIF of creating a WordPress site in Local\"\/><\/figure>\n\n\n\n<p>If you have a pre-existing WordPress site, you can use that as well.<\/p>\n\n\n\n<p>After you\u2019ve got a basic WordPress site either locally or on a server somewhere, you can install the WPGraphQL plugin from the plugin repository and activate it.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2022\/10\/Screen-Shot-2022-10-25-at-11.50.06-AM.png\" alt=\"A screenshot of WPGraphQL in the plugin repository\"\/><\/figure>\n\n\n\n<p>After you install and activate the plugin, you gain access to a GraphQL menu option that provides you with an interactive IDE called GraphiQL that you can use to construct and test your GraphQL queries.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2022\/10\/Screen-Shot-2022-10-25-at-11.51.02-AM-1024x661.png\" alt=\"A screenshot of the GraphiQL IDE interface\"\/><\/figure>\n\n\n\n<p>By default, WPGraphQL makes a GraphQL endpoint available at the <code>\/graphql<\/code> path of your site domain.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating a Dynamic Index Page<\/h2>\n\n\n\n<p>The first step in getting data from your WordPress site is making the URL to your WPGraphQL endpoint available in the Nuxt config file. For this project, you will add this as a <a href=\"https:\/\/nuxt.com\/docs\/guide\/going-further\/runtime-config\">runtime configuration variable<\/a> instead of in a <code>.env<\/code> file. Open your Nuxt config file and add an additional key to the configuration object called <code>runtimeConfig<\/code>, which can accept both public and private values. You can add your WordPress URL as you see in the example below:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" 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-comment\">\/\/ https:\/\/nuxt.com\/docs\/api\/configuration\/nuxt-config<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> defineNuxtConfig({\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">modules<\/span>: &#91;\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-string\">'@nuxt\/devtools'<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-string\">'@nuxtjs\/tailwindcss'<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    ],\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">runtimeConfig<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">public<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>            <span class=\"hljs-attr\">wordpressUrl<\/span>: <span class=\"hljs-string\">'https:\/\/acfheadless.wpengine.com\/graphql'<\/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-8\"><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>With this value in place, you can access your WordPress URL from inside your Nuxt application using <code>config.public.wordpressUrl<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Query WPGraphQL using useFetch<\/h3>\n\n\n\n<p>To make the connection between our Nuxt application and your WordPress site, you will also need to add some data-fetching code to your <code>index.vue<\/code> file. This data-fetching code will live inside the <code>script<\/code> block of the route component.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" 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\">script<\/span> <span class=\"hljs-attr\">setup<\/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\">const<\/span> route = useRoute()<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">const<\/span> config = useRuntimeConfig();<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">const<\/span> { data, refresh, pending } = <span class=\"hljs-keyword\">await<\/span> useFetch(config.public.wordpressUrl, {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"> <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'get'<\/span>,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"> <span class=\"hljs-attr\">query<\/span>: {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">   <span class=\"hljs-attr\">query<\/span>: <span class=\"hljs-string\">`<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">     query NewQuery {<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">       posts(first:10){<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">         nodes {<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">           title<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">           date<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">           excerpt<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">           uri<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">         }<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">       }<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">     }`<\/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\">transform(data){<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">return<\/span> data.data.posts.nodes <span class=\"hljs-keyword\">as<\/span> <span class=\"hljs-built_in\">Array<\/span>&lt;Record&lt;<span class=\"hljs-string\">'title'<\/span> | <span class=\"hljs-string\">'date'<\/span> | <span class=\"hljs-string\">'excerpt'<\/span> | <span class=\"hljs-string\">'uri'<\/span>, string&gt;&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>\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-9\"><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>There is a lot going on in this section of code so let&#8217;s spend some time unpacking it. First, you need to make the runtime config values available by calling the <a href=\"https:\/\/nuxt.com\/docs\/api\/composables\/use-runtime-config\"><code>useRuntimeConfig<\/code> composable<\/a>. From there, you can use the <a href=\"https:\/\/nuxt.com\/docs\/getting-started\/data-fetching#usefetch\"><code>useFetch<\/code> composable<\/a> to make a network request to your WordPress site. This particular API has <a href=\"https:\/\/nuxt.com\/docs\/api\/composables\/use-fetch\">a ton of options<\/a> that are worth exploring.&nbsp;<\/p>\n\n\n\n<p>In this example, you are making a <code>GET<\/code> request to your WordPress site and passing your GraphQL query as a query parameter. This GraphQL query will get the 10 most recent posts and include the title, date, excerpt, and URI. Since this is a simple query, you can use a <code>GET<\/code> request instead of a <code>POST<\/code> request to take advantage of any network caching that your host may enable.<\/p>\n\n\n\n<p>Instead of returning the raw result, the <code>useFetch<\/code> composable also accepts a <code>transform<\/code> callback that lets you process the data returned from your network call. In this example, you dig into the data returned from WPGraphQL to get only the relevant posts and then add some additional typing that will help Nuxt auto-complete your code as you type.&nbsp; All of the variables you have created in this component\u2019s <code>script<\/code> block are available inside the component&#8217;s <code>template<\/code> as well.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implement a Post Component<\/h3>\n\n\n\n<p>Now that you have some data from WordPress, you can create a component to display the posts on your index page. Inside your <code>components<\/code> folder, create a new file called <code>Post.vue<\/code>.&nbsp; This file will have both a <code>script<\/code> and a <code>template<\/code> block with the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" 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\">NuxtLink<\/span> <span class=\"hljs-attr\">:to<\/span>=<span class=\"hljs-string\">'post.uri'<\/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\">\"flex<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       items-center<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       bg-gradient-to-r<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       from-cyan-500<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       to-blue-500<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       p-8<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       rounded-lg<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       text-white<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       transition-all<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       hover:-translate-y-1<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"hljs-string\">       hover:scale-105\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">       &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\">h2<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"font-semibold text-2xl\"<\/span>&gt;<\/span>{{ post.title }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>               <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{{ new Date(post.date).toLocaleDateString() }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/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\">NuxtLink<\/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><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">setup<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"actionscript\"><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"actionscript\"><span class=\"hljs-keyword\">const<\/span> props = defineProps&lt;{<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"actionscript\">   post: Record&lt;<span class=\"hljs-string\">'title'<\/span> | <span class=\"hljs-string\">'date'<\/span> | <span class=\"hljs-string\">'excerpt'<\/span> | <span class=\"hljs-string\">'uri'<\/span>, string&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"actionscript\">}&gt;();<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"actionscript\"><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"actionscript\"><\/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><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-10\"><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>Let&#8217;s examine the <code>script<\/code> block first. In this component, you&#8217;ll need to define the <code>props<\/code> that it will accept. Since the data you got back from WPGraphQL already has individual posts formatted as objects, you can just pass the entire object as a single <code>post<\/code> prop. To register <code>props<\/code> on this component, you can use the <a href=\"https:\/\/vuejs.org\/api\/sfc-script-setup.html#defineprops-defineemits\"><code>defineProps<\/code><\/a> API and pure-type syntax to type your <code>post<\/code> prop. You can also do this in a more conventional manner by passing its configuration object directly to the <a href=\"https:\/\/vuejs.org\/api\/sfc-script-setup.html#defineprops-defineemits\">defineProps<\/a> composable.<\/p>\n\n\n\n<p><br>Now that your component can accept <code>props<\/code>, let&#8217;s focus on the <code>template<\/code> block. At the topmost level, you have the <code>NuxtLink<\/code> component wrapping a few other <code>div<\/code>s that contain your styles and interpolate your data. The <a href=\"https:\/\/nuxt.com\/docs\/api\/components\/nuxt-link\"><code>NuxtLink<\/code> component<\/a> can be used for both internal and external links, and Nuxt intelligently will apply optimizations to them based on the target location. In this example, the <code>to<\/code> attribute will be the value of the current post\u2019s URI.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" 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\">NuxtLink<\/span> <span class=\"hljs-attr\">:to<\/span>=<span class=\"hljs-string\">'post.uri'<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">NuxtLink<\/span>&gt;<\/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\">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>Inside the link, you can add some additional Tailwind styles to modify the appearance of the post component. To display the other data from your WordPress post, you can use Vue\u2019s <a href=\"https:\/\/vuejs.org\/guide\/essentials\/template-syntax.html#text-interpolation\">text interpolation syntax<\/a>, which is also known as mustache syntax <code>{{}}<\/code>, to display your text values. In the case of the post date, you can also include <a href=\"https:\/\/vuejs.org\/guide\/essentials\/template-syntax.html#using-javascript-expressions\">JavaScript expressions<\/a> if you need to do any further data manipulation:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" 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\">h2<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"font-semibold text-2xl\"<\/span>&gt;<\/span>{{ post.title }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{{ new Date(post.date).toLocaleDateString() }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/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\">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 creating the <code>Post<\/code> component, you will need to use the component on the <code>index.vue<\/code> route to display the list of posts. To do this, you can use a <a href=\"https:\/\/vuejs.org\/api\/built-in-directives.html#v-for\"><code>v-for<\/code> directive<\/a> to render a post component for each post returned from WordPress. By using the <code>post in data<\/code> syntax, you create a local <code>post<\/code> variable that can be passed to other component attributes. Like other frameworks, Vue needs a <code>:key<\/code> attribute that is unique, so you can use the <code>post.uri<\/code> value for that. Then you can pass the current post to the <code>Post<\/code> component using the <code>post<\/code> prop.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" 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>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TheHeader<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TheHeader<\/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\">\"grid gap-8 grid-cols-1 lg:grid-cols-3 p-6\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Post<\/span> <span class=\"hljs-attr\">v-for<\/span>=<span class=\"hljs-string\">\"post in data\"<\/span> <span class=\"hljs-attr\">:key<\/span>=<span class=\"hljs-string\">\"post.uri\"<\/span> <span class=\"hljs-attr\">:post<\/span>=<span class=\"hljs-string\">\"post\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Post<\/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\">template<\/span>&gt;<\/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\">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 your application rerenders, you should see a screen that looks like this if you visit the index route of your site.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"617\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-index-page-posts-1024x617.png\" alt=\"A screenshot of the index route pulling in the 10 most recent posts\" class=\"wp-image-5274\" srcset=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-index-page-posts-1024x617.png 1024w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-index-page-posts-300x181.png 300w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-index-page-posts-768x463.png 768w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-index-page-posts.png 1218w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>If you hover over the cards, you should see CSS animations applied with Tailwind, and each link should route you to the URI for that particular post. In the next steps, you will enhance that route to display dynamic data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create Dynamic Post Detail Pages<\/h2>\n\n\n\n<p>Now that you have a dynamic index page, you can shift your focus to creating post-detail pages. Since this route component will only display content for one post at a time, you can build that layout directly into your page component.&nbsp; Open up your <code>[...uri].vue<\/code> file and copy the following code into that component:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" 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>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TheHeader<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TheHeader<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>       <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"bg-gray-100 container mx-auto mt-6 p-6 rounded-lg\"<\/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-4xl\"<\/span>&gt;<\/span>{{ data.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-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-2xl mt-4\"<\/span>&gt;<\/span>{{ new Date(data.date).toLocaleDateString() }}<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> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mt-4 space-y-2\"<\/span> <span class=\"hljs-attr\">v-html<\/span>=<span class=\"hljs-string\">\"data.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\">main<\/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\">setup<\/span>&gt;<\/span><span class=\"javascript\"><\/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\">const<\/span> route = useRoute();<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">const<\/span> uri = route.params.uri.join(<span class=\"hljs-string\">'\/'<\/span>);<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">const<\/span> config = useRuntimeConfig();<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-keyword\">const<\/span> {data, pending, refresh, error} = <span class=\"hljs-keyword\">await<\/span> useFetch(config.public.wordpressUrl, {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">   <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'get'<\/span>,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">   <span class=\"hljs-attr\">query<\/span>: {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">       <span class=\"hljs-attr\">query<\/span>: <span class=\"hljs-string\">`<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">       query MyQuery3($uri: String!) {<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">           nodeByUri(uri: $uri) {<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">               ... on Post {<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">                   id<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">                   title<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">                   date<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">                   content<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">               }<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">           }<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">       }<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\"><span class=\"hljs-string\">       `<\/span>,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">       <span class=\"hljs-attr\">variables<\/span>: {<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">           <span class=\"hljs-attr\">uri<\/span>: uri<\/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\">   transform(data){<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">       <span class=\"hljs-keyword\">return<\/span> data.data.nodeByUri<\/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\">useHead({<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\"><span class=\"javascript\">   <span class=\"hljs-attr\">title<\/span>: data.value.title<\/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-14\"><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>Let&#8217;s start by breaking down the script block. The first thing to call out is how you handle extracting the URI <code>params<\/code> from the current route using the <a href=\"https:\/\/nuxt.com\/docs\/api\/composables\/use-route#useroute\"><code>useRoute<\/code> composable<\/a>. Since this route utilizes a catch-all, <code>route.params.uri<\/code> is an array instead of a string. To make these array items usable inside your query, you need to <code>join<\/code> them using a forward slash:<\/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\">const<\/span> uri = route.params.uri.join(<span class=\"hljs-string\">'\/'<\/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>Now that the URI for the route is stored in a variable, you can use the <code>useFetch<\/code> helper to make another network request to WPGraphQL:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" 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> {data, pending, refresh, error} = await useFetch(config.<span class=\"hljs-keyword\">public<\/span>.wordpressUrl, {\n<\/span><\/span><span class='shcb-loc'><span>   method: <span class=\"hljs-string\">'get'<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>   query: {\n<\/span><\/span><span class='shcb-loc'><span>       query: `\n<\/span><\/span><span class='shcb-loc'><span>       query MyQuery3($uri: String!) {\n<\/span><\/span><span class='shcb-loc'><span>           nodeByUri(uri: $uri) {\n<\/span><\/span><span class='shcb-loc'><span>               ... on Post {\n<\/span><\/span><span class='shcb-loc'><span>                   id\n<\/span><\/span><span class='shcb-loc'><span>                   title\n<\/span><\/span><span class='shcb-loc'><span>                   date\n<\/span><\/span><span class='shcb-loc'><span>                   content\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>       variables: {\n<\/span><\/span><span class='shcb-loc'><span>           uri: uri\n<\/span><\/span><span class='shcb-loc'><span>       }\n<\/span><\/span><span class='shcb-loc'><span>   },\n<\/span><\/span><span class='shcb-loc'><span>   transform(data){\n<\/span><\/span><span class='shcb-loc'><span>       <span class=\"hljs-keyword\">return<\/span> data.data.nodeByUri\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><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><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>The shape of this code should look very similar to the data fetching you did for your index page. However, instead of requesting a list of posts, this query utilizes a variable to get a specific post using the URI you extract from the route using <a href=\"https:\/\/www.wpgraphql.com\/2021\/12\/23\/query-any-page-by-its-path-using-wpgraphql\">the nodeByUri query<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">GraphQL Queries with Variables<\/h3>\n\n\n\n<p>Let&#8217;s break down a few parts of this query to examine how variables work in GraphQL. When you give your query an <a href=\"https:\/\/graphql.org\/learn\/queries\/#operation-name\">operation name<\/a>, you also specify the <a href=\"https:\/\/graphql.org\/learn\/queries\/#variables\">variable arguments<\/a> that the query will take along with their types and whether or not they are required, indicated by the exclamation point following the type. Since this query could potentially return multiple different content types you can use <a href=\"https:\/\/graphql.org\/learn\/queries\/#inline-fragments\">an inline fragment<\/a> on the post type to get properties only on that specific type:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" 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>   query MyQuery3($uri: String!) {\n<\/span><\/span><span class='shcb-loc'><span>           nodeByUri(uri: $uri) {\n<\/span><\/span><span class='shcb-loc'><span>               ... on Post {\n<\/span><\/span><span class='shcb-loc'><span>                   id\n<\/span><\/span><span class='shcb-loc'><span>                   title\n<\/span><\/span><span class='shcb-loc'><span>                   date\n<\/span><\/span><span class='shcb-loc'><span>                   content\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-17\"><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>To pass a value into your query\u2019s variable argument, you need to add another key to your fetch call\u2019s query params that specifies the names of the variables and their values. When this query is evaluated by the GraphQL server, the values provided by the variables key will be substituted inside of your query:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" 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\">variables<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attribute\">uri<\/span>: uri\n<\/span><\/span><span class='shcb-loc'><span> }\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><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>As in the previous example, you can also use the <code>transform<\/code> option on <code>useFetch<\/code> to directly return the data from your GraphQL query.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">SEO with Nuxt 3<\/h3>\n\n\n\n<p>Once you have post data available in your <code>script<\/code> block, you can make a quick call using the <a href=\"https:\/\/nuxt.com\/docs\/api\/composables\/use-head\"><code>useHead<\/code> composable<\/a> to set the page title. Nuxt 3 also provides some <a href=\"https:\/\/nuxt.com\/docs\/getting-started\/seo-meta#useseometa-and-useserverseometa\">other methods of manipulating SEO data<\/a> that help you avoid common mistakes with <code>meta<\/code> property names.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" 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\">useHead<\/span>({\n<\/span><\/span><span class='shcb-loc'><span>   <span class=\"hljs-attribute\">title<\/span>: data.value.title\n<\/span><\/span><span class='shcb-loc'><span>})\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><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<h3 class=\"wp-block-heading\">Render HTML Content<\/h3>\n\n\n\n<p>Now that you have an individual post\u2019s details stored in the <code>data<\/code> variable, you can use those values inside of your <code>template<\/code> block.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" 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>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TheHeader<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TheHeader<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>       <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"bg-gray-100 container mx-auto mt-6 p-6 rounded-lg\"<\/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-4xl\"<\/span>&gt;<\/span>{{ data.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-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"text-2xl mt-4\"<\/span>&gt;<\/span>{{ new Date(data.date).toLocaleDateString() }}<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> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mt-4 space-y-2\"<\/span> <span class=\"hljs-attr\">v-html<\/span>=<span class=\"hljs-string\">\"data.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\">main<\/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><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><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>Most of the text interpolation examples in this piece of code should look very similar to the previous examples you&#8217;ve already created. However, since you&#8217;re dealing with post content returned as raw HTML, you need to use a different Vue directive to display that content on the page. To display raw HTML, you can add the  <a href=\"https:\/\/vuejs.org\/api\/built-in-directives.html#v-html\"><code>v-html<\/code> directive<\/a> to an element to render the HTML inside of the element:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" 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\">article<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mt-4 space-y-2\"<\/span> <span class=\"hljs-attr\">v-html<\/span>=<span class=\"hljs-string\">\"data.content\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><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>Much like React\u2019s <code>dangerouslySetInnerHTML<\/code> attribute, including user-supplied HTML here does open some security concerns, but WordPress already has some <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_kses\/\">built-in mechanisms to protect you from cross-site scripting attacks<\/a>.<\/p>\n\n\n\n<p>Once your application refreshes, visit one of the post URI routes and you should see a page that looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"798\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-post-details-page-1024x798.png\" alt=\"A post detail page rendering text and images\" class=\"wp-image-5275\" srcset=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-post-details-page-1024x798.png 1024w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-post-details-page-300x234.png 300w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-post-details-page-768x599.png 768w, https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/rendered-post-details-page.png 1243w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Amazing! Now that you have a fully functioning Nuxt application pulling data from your WordPress site, you can explore different deployment methods in the next step of this tutorial.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy Your Nuxt Site<\/h2>\n\n\n\n<p>Nuxt 3 offers a number of different deployment options depending on your use case.&nbsp;<\/p>\n\n\n\n<p>If you want to statically generate your entire site, including creating a static version of your API payloads, you can run the following command:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>npx nuxi generate\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The built files will be available in the <code>.output\/public directory<\/code>, but in some cases, you may also need a file server in front of this folder to serve those static files.<\/p>\n\n\n\n<p>To deploy the project to a Node.js server, you can run the following command:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>npm run nuxt build\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This will generate an entry file called <code>.output\/server\/index.mjs<\/code>, and you can change your <code>start<\/code> command in <code>package.json<\/code> to the following command:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>node .output\/server\/index.mjs\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If you are interested in deploying your headless WordPress &amp; Nuxt 3 site on <a href=\"https:\/\/wpengine.com\/headless-wordpress\">the Atlas platform<\/a>, you can follow <a href=\"https:\/\/developers.wpengine.com\/docs\/atlas\/framework-guides\/nuxt\">the framework guide for Nuxt 3<\/a>. Each Atlas instance comes with hosting environments for both WordPress and Node.js applications and supports some of the awesome features listed below:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Git-based CI\/CD<\/li>\n\n\n\n<li>PR Preview Environments<\/li>\n\n\n\n<li>Build Webhooks<\/li>\n\n\n\n<li>Optimized Infrastructure for Headless WordPress<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>Excellent! Hopefully, you have a better idea of how to work with headless WordPress and Nuxt 3. After reading this tutorial, you should be able to implement Nuxt 3 routing, use WordPress with WPGraphQL to fetch data and deploy your Nuxt project.  <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, you\u2019ll learn how to build a basic headless WordPress site using Nuxt 3 and Vue 3. Nuxt 3 is a full-stack framework built around the latest version [&hellip;]<\/p>\n","protected":false},"author":19,"featured_media":5359,"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":[43],"class_list":["post-5237","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-headless","tag-popular-2023"],"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 Nuxt 3 &amp; Vue 3 - Builders<\/title>\n<meta name=\"description\" content=\"In this article, you\u2019ll use Nuxt 3 and Vue 3 to build a basic headless WordPress site. Nuxt 3 is a full-stack framework built around the latest version of the Vue JavaScript framework.\" \/>\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-nuxt-3-vue-3\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Headless WordPress with Nuxt 3 &amp; Vue 3 - Builders\" \/>\n<meta property=\"og:description\" content=\"In this article, you\u2019ll use Nuxt 3 and Vue 3 to build a basic headless WordPress site. Nuxt 3 is a full-stack framework built around the latest version of the Vue JavaScript framework.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/\" \/>\n<meta property=\"og:site_name\" content=\"Builders\" \/>\n<meta property=\"article:published_time\" content=\"2023-05-26T16:05:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-20T13:39:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Jeff Everhart\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg\" \/>\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=\"Jeff Everhart\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 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-nuxt-3-vue-3\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/\"},\"author\":{\"name\":\"Jeff Everhart\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/person\\\/b5a7f380738d25f57b00a5aaacf3db52\"},\"headline\":\"Headless WordPress with Nuxt 3 &#038; Vue 3\",\"datePublished\":\"2023-05-26T16:05:48+00:00\",\"dateModified\":\"2023-12-20T13:39:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/\"},\"wordCount\":2656,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2023\\\/05\\\/img-opengraph-sitecover-1.jpg\",\"keywords\":[\"popular-2023\"],\"articleSection\":[\"Headless\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/\",\"name\":\"Headless WordPress with Nuxt 3 & Vue 3 - Builders\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2023\\\/05\\\/img-opengraph-sitecover-1.jpg\",\"datePublished\":\"2023-05-26T16:05:48+00:00\",\"dateModified\":\"2023-12-20T13:39:43+00:00\",\"description\":\"In this article, you\u2019ll use Nuxt 3 and Vue 3 to build a basic headless WordPress site. Nuxt 3 is a full-stack framework built around the latest version of the Vue JavaScript framework.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/#primaryimage\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2023\\\/05\\\/img-opengraph-sitecover-1.jpg\",\"contentUrl\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2023\\\/05\\\/img-opengraph-sitecover-1.jpg\",\"width\":1200,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/headless-wordpress-nuxt-3-vue-3\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Headless WordPress with Nuxt 3 &#038; Vue 3\"}]},{\"@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\\\/b5a7f380738d25f57b00a5aaacf3db52\",\"name\":\"Jeff Everhart\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/237d84b2a63acb8c427ba3246f9c5fc1b436aac578a5df421927c23b4fde45f5?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/237d84b2a63acb8c427ba3246f9c5fc1b436aac578a5df421927c23b4fde45f5?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/237d84b2a63acb8c427ba3246f9c5fc1b436aac578a5df421927c23b4fde45f5?s=96&d=mm&r=g\",\"caption\":\"Jeff Everhart\"},\"description\":\"Jeff is a Senior Developer Advocate at WP Engine, focusing on educational resources that blend JavaScript and WordPress to support the Atlas headless WordPress platform and ecosystem.\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/author\\\/jeff-everhartwpengine-com\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Headless WordPress with Nuxt 3 & Vue 3 - Builders","description":"In this article, you\u2019ll use Nuxt 3 and Vue 3 to build a basic headless WordPress site. Nuxt 3 is a full-stack framework built around the latest version of the Vue JavaScript framework.","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-nuxt-3-vue-3\/","og_locale":"en_US","og_type":"article","og_title":"Headless WordPress with Nuxt 3 & Vue 3 - Builders","og_description":"In this article, you\u2019ll use Nuxt 3 and Vue 3 to build a basic headless WordPress site. Nuxt 3 is a full-stack framework built around the latest version of the Vue JavaScript framework.","og_url":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/","og_site_name":"Builders","article_published_time":"2023-05-26T16:05:48+00:00","article_modified_time":"2023-12-20T13:39:43+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg","type":"image\/jpeg"}],"author":"Jeff Everhart","twitter_card":"summary_large_image","twitter_image":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg","twitter_creator":"@wpebuilders","twitter_site":"@wpebuilders","twitter_misc":{"Written by":"Jeff Everhart","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#article","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/"},"author":{"name":"Jeff Everhart","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/b5a7f380738d25f57b00a5aaacf3db52"},"headline":"Headless WordPress with Nuxt 3 &#038; Vue 3","datePublished":"2023-05-26T16:05:48+00:00","dateModified":"2023-12-20T13:39:43+00:00","mainEntityOfPage":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/"},"wordCount":2656,"commentCount":0,"publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"image":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#primaryimage"},"thumbnailUrl":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg","keywords":["popular-2023"],"articleSection":["Headless"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/","url":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/","name":"Headless WordPress with Nuxt 3 & Vue 3 - Builders","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/#website"},"primaryImageOfPage":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#primaryimage"},"image":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#primaryimage"},"thumbnailUrl":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg","datePublished":"2023-05-26T16:05:48+00:00","dateModified":"2023-12-20T13:39:43+00:00","description":"In this article, you\u2019ll use Nuxt 3 and Vue 3 to build a basic headless WordPress site. Nuxt 3 is a full-stack framework built around the latest version of the Vue JavaScript framework.","breadcrumb":{"@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#primaryimage","url":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg","contentUrl":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2023\/05\/img-opengraph-sitecover-1.jpg","width":1200,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/wpengine.com\/builders\/headless-wordpress-nuxt-3-vue-3\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wpengine.com\/builders\/"},{"@type":"ListItem","position":2,"name":"Headless WordPress with Nuxt 3 &#038; Vue 3"}]},{"@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\/b5a7f380738d25f57b00a5aaacf3db52","name":"Jeff Everhart","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/237d84b2a63acb8c427ba3246f9c5fc1b436aac578a5df421927c23b4fde45f5?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/237d84b2a63acb8c427ba3246f9c5fc1b436aac578a5df421927c23b4fde45f5?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/237d84b2a63acb8c427ba3246f9c5fc1b436aac578a5df421927c23b4fde45f5?s=96&d=mm&r=g","caption":"Jeff Everhart"},"description":"Jeff is a Senior Developer Advocate at WP Engine, focusing on educational resources that blend JavaScript and WordPress to support the Atlas headless WordPress platform and ecosystem.","url":"https:\/\/wpengine.com\/builders\/author\/jeff-everhartwpengine-com\/"}]}},"_links":{"self":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/5237","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\/19"}],"replies":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/comments?post=5237"}],"version-history":[{"count":0,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/5237\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/media\/5359"}],"wp:attachment":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/media?parent=5237"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/categories?post=5237"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/tags?post=5237"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}