Skip to content
← blog

Apr 7, 2026 · 5 min read

What's New in WPNuxt 2.2

Cursor-based pagination, infinite scroll, reactive params, type guards, ACF helpers, and webhook cache revalidation — WPNuxt keeps shipping

Wouter Vernaillen

Wouter Vernaillen

Full Stack Developer

What's New in WPNuxt 2.2

WPNuxt 2.0 shipped on March 14 with type-safe composables, multi-layer caching, Gutenberg block rendering, authentication, and an AI-powered MCP server. Three weeks and two minor releases later, several features that were on the 2.0 roadmap are now production-ready — along with a few that weren’t planned at all.

This post covers what’s new in WPNuxt 2.1 and 2.2. If you’re new to WPNuxt, start with the 2.0 announcement for the full picture.


Quick Recap: What WPNuxt 2.0 Brought

WPNuxt connects WordPress with Nuxt via GraphQL, generating fully typed composables from your queries. Version 2.0 introduced:

  • Type-safe composables generated from GraphQL queries with full autocomplete
  • Three-layer caching — server (Nitro SWR), client deduplication, and SSR payload
  • Gutenberg block rendering with 10 built-in Vue components via @wpnuxt/blocks
  • Authentication with password, OAuth, and external provider support via @wpnuxt/auth
  • AI-powered development via MCP server integration
  • Serverless-ready deployment — no jsdom, works on Vercel out of the box
  • SSG support with prerender route fetching
  • GraphQL mutations — generated useMutation*() composables

All three packages (@wpnuxt/core, @wpnuxt/blocks, @wpnuxt/auth) are now at version 2.2.1.


Cursor-Based Pagination & Infinite Scroll

The most requested feature from the 2.0 roadmap. The new useWPConnection composable handles cursor-based pagination with built-in infinite scroll support:

ts
const { data: posts, pageInfo, loadMore, pending } = await useWPConnection(
  'Posts',
  ['posts'],
  true,
  () => ({ limit: 10 })
)

data returns the accumulated nodes array. pageInfo provides hasNextPage, hasPreviousPage, startCursor, and endCursor. Calling loadMore() fetches the next page and appends the results — perfect for infinite scroll:

vue
<template>
  <div>
    <article v-for="post in posts" :key="post.id">
      <h2>{{ post.title }}</h2>
    </article>
    <button v-if="pageInfo?.hasNextPage" :disabled="pending" @click="loadMore()">
      Load more
    </button>
  </div>
</template>

Calling refresh() resets the accumulation and re-fetches from the beginning.


Reactive Parameters

Generated composables now accept reactive parameters via refs, computed values, or getter functions. When the parameters change, the composable automatically re-fetches:

ts
const orderField = ref('DATE')
const order = ref('DESC')

const { data: posts } = await usePosts(() => ({
  orderField: orderField.value,
  order: order.value
}))

Change orderField or order and the query re-executes. Watch-triggered re-fetches automatically skip the cache so you always get fresh data.

This works with all generated composables — usePosts, usePageByUri, usePostByUri, custom queries, and useWPConnection.


Orderby Variables in Default Queries

The default Posts, PostsByCategoryName, and PostsByCategoryId queries now accept order and orderField variables:

ts
// Sort by title ascending
const { data: posts } = await usePosts({
  orderField: 'TITLE',
  order: 'ASC'
})

// Sort by comment count, most commented first
const { data: popular } = await usePostsByCategoryName({
  categoryName: 'tutorials',
  orderField: 'COMMENT_COUNT',
  order: 'DESC'
})

Available order fields: DATE, TITLE, MODIFIED, AUTHOR, COMMENT_COUNT. Defaults are DATE / DESC — matching WordPress behavior, so existing code is unaffected.


Type Guards for Content Types

Three new type guard helpers make content type narrowing clean and type-safe:

ts
import { isPage, isPost, isContentType } from '#imports'

const { data: node } = await useNodeByUri({ uri: route.path })

if (isPage(node.value)) {
  // TypeScript knows this is a Page — access page-specific fields
  console.log(node.value.isFrontPage)
}

if (isPost(node.value)) {
  // TypeScript knows this is a Post
  console.log(node.value.categories)
}

// Works with custom post types too
if (isContentType(node.value, 'event')) {
  console.log(node.value.contentTypeName) // 'event'
}

All three are auto-imported and narrow the TypeScript type, so downstream code gets full autocomplete for the matched content type.


ACF Field Helpers

Working with Advanced Custom Fields through WPGraphQL often means dealing with quirky data shapes. Two new helpers smooth this out:

unwrapScalar

WPGraphQL types ACF select and radio fields as arrays, even for single-value selections. unwrapScalar normalizes this:

ts
// ACF returns ['upcoming'] for a single-select field
const status = computed(() => unwrapScalar(event.value?.eventDetails?.eventStatus))
// → 'upcoming' (not ['upcoming'])

unwrapConnection

WPGraphQL wraps ACF relationship and post object fields in a connection structure. unwrapConnection extracts the first node:

ts
// ACF returns { nodes: [{ id: '1', title: 'Main Hall' }] } for a single relationship
const venue = computed(() => unwrapConnection(event.value?.eventDetails?.eventVenue))
// → { id: '1', title: 'Main Hall' }

Both return undefined for null or empty values, making them safe to use in computed properties and templates.


Webhook Cache Revalidation

WPNuxt 2.0 already had multi-layer caching. Version 2.2 adds a webhook endpoint so WordPress can invalidate the cache immediately when content changes — no more waiting for the TTL to expire.

Enable it with a shared secret:

nuxt.config.tsts
export default defineNuxtConfig({
  wpNuxt: {
    cache: {
      enabled: true,
      maxAge: 300,
      swr: true,
      revalidateSecret: process.env.WPNUXT_REVALIDATE_SECRET
    }
  }
})

This registers a POST /api/_wpnuxt/revalidate endpoint. Configure a WordPress webhook (e.g. via WP Webhooks or a simple save_post action) to call it with the secret token when content is published or updated.

On Vercel, when VERCEL_TOKEN and VERCEL_PROJECT_ID environment variables are set, the endpoint also purges the Vercel CDN cache using cache tags — giving you near-instant content updates without a full redeploy.

On self-hosted deployments, it purges Nitro’s internal handler cache directly.


Deeper Inner Block Nesting

The @wpnuxt/blocks package now supports deeper nested inner blocks in Gutenberg content. Complex layouts with groups, columns, and nested containers render correctly without losing content at deeper levels. Block types have been consolidated for more consistent handling across nesting levels.


Upgrading

All features are backward-compatible. Update your packages to get everything:

bash
pnpm update @wpnuxt/core @wpnuxt/blocks @wpnuxt/auth

No configuration changes required — existing projects pick up the new composables and helpers through auto-imports.


What’s Next

With pagination, infinite scroll, and deeper block nesting shipped, the remaining roadmap items are:

  • Additional default queries for taxonomies and search
  • End-to-end tutorials for common use cases
  • Media handling deep dive with @nuxt/image optimization patterns

Feedback and feature requests are welcome on the GitHub repository.


Resources

share /