Getting Started

Quick Start Tutorial

Build a blog with WPNuxt in 15 minutes

Build a working blog with WPNuxt from scratch. This tutorial covers fetching posts, displaying content, and creating dynamic pages.

Prerequisites

  • Node.js 20+
  • A WordPress site with WPGraphQL installed
  • Basic familiarity with Vue and Nuxt
Don't have a WordPress site? Use our demo: https://wordpress.wpnuxt.com

Step 1: Create a Nuxt Project

npx nuxi@latest init my-wpnuxt-blog
cd my-wpnuxt-blog
pnpm install

Step 2: Install WPNuxt

pnpm add @wpnuxt/core

Step 3: Configure

Create or update nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@wpnuxt/core'],

  wpNuxt: {
    wordpressUrl: 'https://wordpress.wpnuxt.com'
  }
})

Or use an environment variable:

.env
WPNUXT_WORDPRESS_URL=https://wordpress.wpnuxt.com

Step 4: Generate Types

Run prepare to download the GraphQL schema and generate types:

pnpm nuxt prepare

You should see:

[wpnuxt] WPNuxt module loaded in XXXms

Step 5: Create the Home Page

Replace app.vue with a simple layout, then create the home page.

app.vue
<template>
  <div class="container">
    <NuxtPage />
  </div>
</template>

<style>
.container {
  max-width: 800px;
  margin: 0 auto;
  padding: 2rem;
}
</style>

Create the pages directory and home page:

pages/index.vue
<script setup lang="ts">
// Fetch the 10 most recent posts
const { data: posts } = await usePosts({ first: 10 })
</script>

<template>
  <div>
    <h1>My Blog</h1>

    <div v-if="posts?.length">
      <article v-for="post in posts" :key="post.id">
        <h2>
          <NuxtLink :to="post.uri">
            {{ post.title }}
          </NuxtLink>
        </h2>
        <p>{{ post.date }}</p>
        <div v-sanitize-html="post.excerpt" />
      </article>
    </div>

    <p v-else>No posts found.</p>
  </div>
</template>

<style scoped>
article {
  margin-bottom: 2rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid #eee;
}

h2 {
  margin-bottom: 0.5rem;
}

h2 a {
  color: inherit;
  text-decoration: none;
}

h2 a:hover {
  text-decoration: underline;
}
</style>

Step 6: Start the Dev Server

pnpm dev

Open http://localhost:3000. You should see a list of blog posts!

usePosts() blocks navigation until data is ready — this means the page won't render until posts are loaded, which is ideal for SEO (search engines see the full content). For non-critical content like sidebars, use { lazy: true } to load data in the background without blocking. See Fetching Data for details.

Step 7: Create the Single Post Page

Create a dynamic route for individual posts:

pages/[...slug].vue
<script setup lang="ts">
const route = useRoute()

// Fetch post or page by URI
const { data: node } = await useNodeByUri({ uri: route.path })

// Handle 404
if (!node.value) {
  throw createError({
    statusCode: 404,
    message: 'Page not found'
  })
}

// Set page title
useHead({
  title: node.value.title
})
</script>

<template>
  <article v-if="node">
    <h1>{{ node.title }}</h1>

    <p v-if="'date' in node" class="date">
      Published: {{ new Date(node.date).toLocaleDateString() }}
    </p>

    <div v-sanitize-html="node.content" class="content" />

    <NuxtLink to="/">← Back to home</NuxtLink>
  </article>
</template>

<style scoped>
.date {
  color: #666;
  margin-bottom: 2rem;
}

.content {
  line-height: 1.7;
}

.content :deep(img) {
  max-width: 100%;
  height: auto;
}
</style>

Click on a post title on the home page — you'll now see the full post content!

The [...slug].vue file is a Nuxt catch-all route. It matches any URL path (e.g. /hello-world, /about, /blog/my-post). The useNodeByUri() composable sends that path to WordPress and asks "what content lives at this URI?" — WordPress returns a post, page, or any content type registered at that URL.

Step 8: Add a Navigation Menu

Fetch a WordPress menu and display it:

components/SiteNav.vue
<script setup lang="ts">
// Fetch menu by name (created in WordPress Appearance → Menus)
const { data: menuItems } = await useMenu({ name: 'Primary Menu' })
</script>

<template>
  <nav v-if="menuItems?.length">
    <NuxtLink
      v-for="item in menuItems"
      :key="item.id"
      :to="item.uri"
    >
      {{ item.label }}
    </NuxtLink>
  </nav>
</template>

<style scoped>
nav {
  display: flex;
  gap: 1rem;
  margin-bottom: 2rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid #eee;
}

a {
  color: inherit;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}
</style>

Add to your layout:

app.vue
<template>
  <div class="container">
    <SiteNav />
    <NuxtPage />
  </div>
</template>
Create a menu named "Primary Menu" in WordPress under Appearance → Menus. The name parameter matches the menu name (or slug).

Show featured images on the post list:

pages/index.vue
<script setup lang="ts">
const { data: posts } = await usePosts({ first: 10 })
</script>

<template>
  <div>
    <h1>My Blog</h1>

    <div v-if="posts?.length">
      <article v-for="post in posts" :key="post.id">
        <img
          v-if="post.featuredImage?.node?.sourceUrl"
          :src="post.featuredImage.node.sourceUrl"
          :alt="post.featuredImage.node.altText"
          class="featured-image"
        />
        <h2>
          <NuxtLink :to="post.uri">
            {{ post.title }}
          </NuxtLink>
        </h2>
        <div v-sanitize-html="post.excerpt" />
      </article>
    </div>
  </div>
</template>

<style scoped>
.featured-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 8px;
  margin-bottom: 1rem;
}
</style>

What You've Learned

In this tutorial you've used the key building blocks of a WPNuxt project:

  • usePosts() — Fetch a list of posts with auto-generated composables
  • useNodeByUri() — Resolve any WordPress URL to its content
  • useMenu() — Fetch editor-managed navigation menus
  • [...slug].vue — Catch-all route pattern for dynamic WordPress content
  • v-sanitize-html — Safely render WordPress HTML content

What's Next?

You now have a working blog! Here's where to go from here:

Complete Code

Here's the final project structure:

my-wpnuxt-blog/
├── app.vue
├── nuxt.config.ts
├── pages/
│   ├── index.vue
│   └── [...slug].vue
├── components/
│   └── SiteNav.vue
└── .env

Troubleshooting

"Cannot find module" errors

Run pnpm nuxt prepare to regenerate types.

No posts showing

  1. Check that WordPress has published posts
  2. Verify WPGraphQL is installed and activated
  3. Test the GraphQL endpoint: https://your-wordpress.com/graphql
  1. Create a menu in WordPress under Appearance → Menus
  2. Assign it to the "Primary" location
  3. Check that menu items are published pages/posts
Copyright © 2026