Next.js, Headless WordPress
MentoNext , Headless WordPress package
Headless WordPress for Next.js. Typed. Normalized. Yours to Configure.
Most headless WordPress setups start the same way: a hand-rolled fetch wrapper, a different SEO mapper for every plugin a client happens to run, and a caching strategy baked in by whoever wrote the adapter. mentonext replaces all of that with one typed REST client — posts, pages, custom post types, authors, menus, and search, normalized SEO across Yoast, RankMath, and AIOSEO, React hooks for client components, and a caching layer that’s entirely pluggable. Open source. MIT licensed. Built for developers who ship more than one headless WordPress project.
01
One typed client for every WordPress REST response.
Posts, pages, custom post types, authors, menus, and search — all mapped to the same consistent, fully typed shape, regardless of how the source site’s REST API is configured. No more guessing field names or writing a parser per project. Call a method, get back data you can trust the shape of.
import { createWPClient } from 'mentonext';
const wp = createWPClient({
baseUrl: 'https://example.com',
});
const { items } = await wp.getPosts({ perPage: 10 });
const post = await wp.getPostBySlug('hello-world');
import { toNextMetadata } from 'mentonext';
export async function generateMetadata({ params }) {
const { slug } = await params;
const post = await wp.getPostBySlug(slug);
// Works whether the site runs Yoast, RankMath, or AIOSEO —
// mentonext detects and normalizes it before this line runs.
return toNextMetadata(post);
}
02
Stop writing a different SEO mapper for every client.
Yoast, RankMath, and AIOSEO each expose meta data differently — and most adapters only support one of them. mentonext’s normalizeSeo detects whichever plugin a site runs and returns the same shape every time: title, description, canonical, OG image, and JSON-LD. Write generateMetadata once, ship it across every client site.
03
Caching is a decision you make, not one we make for you.
Some adapters hardcode a caching strategy and leave you working around it. mentonext ships with a simple in-memory cache for quick starts, but the cache layer is a plain interface — swap in Redis, a CDN-backed store, or disable caching entirely for a site that needs every request live. Your infrastructure decides, not the package.
const wp = createWPClient({
baseUrl: 'https://example.com',
cache: myRedisCacheAdapter,
// or: cache: 'memory' (default)
// or: cache: false — always fetch live
});
'use client';
import { usePosts } from 'mentonext/react';
export function PostList() {
const { data, isLoading, error } = usePosts();
if (isLoading) return <p>Loading…</p>;
return <ul>{data.items.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
04
React hooks for the client, typed helpers for the server.
Client components get usePosts, usePages, useWPClient, and friends — loading and error states included. Server components and static generation get toStaticParams, toJsonLdScriptProps, and getMediaUrl. One package, both rendering models, no duplicated fetch logic between them.
USE CASES
Real problems. Real answers.
Here is what mentonext solves out of the box.
SCENARIO 01 · SEO FRAGMENTATION PROBLEM
Three client sites, three SEO plugins, three different bugs.
Site A runs Yoast. Site B runs RankMath. Site C runs AIOSEO. Each one exposes its meta data differently, so your generateMetadata function either only works for one of them, or grows a pile of plugin-specific if-statements that breaks the next time a client switches plugins.
How mentonext solves it:
- Call
wp.getPostBySlug()as usual — no plugin-specific code - mentonext detects Yoast, RankMath, or AIOSEO automatically
toNextMetadata()maps the normalized shape to Next.js’sMetadata- Ship the same
generateMetadatafunction to every client, regardless of their plugin
One metadata mapper. Any SEO plugin the client happens to run.
3
SEO plugins supported
1
mapping function to write
Zero plugin-specific code
SCENARIO 02 · BOILERPLATE PROBLEM
Every headless project starts with the same 200 lines of fetch wrappers.
Pagination, error handling, response shaping, TypeScript types — you’ve written this code before, for the last client, and the one before that. Hand-rolling a WordPress REST wrapper from scratch is the first thing that eats time on every new headless build.
How mentonext solves it:
npm install mentonextcreateWPClient({ baseUrl })— no further setup- Call
getPosts,getPostBySlug,getPages,getMenu, and more — all fully typed - Never write your own WordPress fetch wrapper again
A typed REST client, not another boilerplate file to maintain.
Zero-config
setup to start
Fully typed
TypeScript, end to end
REST-first, GraphQL adapter planned
SCENARIO 03 · NEXT.JS 16 ERROR-HANDLING PROBLEM
Next.js 16 serves a blank 500 page instead of your error boundary.
On a route using generateStaticParams, Next.js 16 does not route an error thrown while rendering an out-of-list slug on demand through app/error.tsx — it serves a bare, unstyled 500 instead. Most developers discover this the hard way, in production, when the WordPress site is briefly unreachable.
How mentonext solves it:
- Catch the fetch inside the page component, not
app/error.tsx - Distinguish a real 404 (
WPNotFoundError) from any other failure - Render a styled fallback inline instead of re-throwing
- The exact pattern — and why it’s needed — is documented directly in the README
A real Next.js 16 edge case, already diagnosed and documented for you.
Next.js 16
compatible, gotcha included
Documented in the README, not discovered in production
SCENARIO 04 · CACHING RIGIDITY PROBLEM
Your hosting’s cache strategy doesn’t match the adapter’s.
Some adapters cache every response the same way, on every project, whether you’re deployed on Vercel, a VPS, or behind a CDN that already handles caching for you. That mismatch either duplicates caching work or actively fights your infrastructure.
How mentonext solves it:
- Pass any object matching the simple
CacheAdapterinterface - Use the built-in in-memory cache to start, no configuration required
- Swap in Redis, a KV store, or disable caching entirely for SSR-heavy routes
- The decision is yours, project by project
Your infrastructure decides the cache strategy. Not the package.
Pluggable
cache interface
Your call
memory, Redis, or none
No forced caching defaults
Open source. MIT licensed. Live on npm today.
npm install mentonext