本文详解如何使用 Next.js 15 App Router 与 WordPress REST API 整合,实现增量静态再生成(ISR)。

什么是增量静态再生成(ISR)

传统静态生成(SSG):

  • 构建时生成所有页面
  • 内容更新 → 重新构建全部页面 → 慢

增量静态再生成(ISR):

  • 构建时生成部分页面
  • 请求时增量生成其他页面
  • 定时重新验证(revalidate)→ 内容更新自动生效
  • 无需全量重建 → 快

为什么用 Next.js + WordPress

架构:

WordPress(后端CMS) → REST API → Next.js(前端展示)

优势:

  • WordPress 内容管理强(插件丰富、编辑体验好)
  • Next.js 前端性能极致(SSR/SSG/ISR)
  • 分离前后端 → 安全性提升
  • CDN 缓存 → TTFB < 50ms

实战一:搭建 Next.js 15 项目

初始化项目

# 创建 Next.js 15 项目(App Router)

npx create-next-app@latest wp-nextjs --typescript --tailwind --eslint

cd wp-nextjs

安装 WordPress REST API 客户端

npm install @wordpress/api-fetch axios

配置 WordPress REST API 客户端

// lib/wp-api.ts

import axios from 'axios';

const wpApi = axios.create({

baseURL: 'https://www.shenma98.com/wp-json/wp/v2',

headers: {

'Content-Type': 'application/json',

},

});

export async function getPosts(page = 1, perPage = 10) {

const response = await wpApi.get('/posts', {

params: {

page,

per_page: perPage,

_embed: true, // 嵌入媒体/作者信息

},

});

return response.data;

}

export async function getPost(slug: string) {

const response = await wpApi.get('/posts', {

params: {

slug,

_embed: true,

},

});

return response.data[0];

}

export async function getCategories() {

const response = await wpApi.get('/categories');

return response.data;

}

实战二:实现 ISR(增量静态再生成)

首页(文章列表)- ISR 配置

// app/page.tsx

import { getPosts } from '@/lib/wp-api';

import Link from 'next/link';

export const revalidate = 60; // ISR:每60秒重新验证一次

export default async function HomePage() {

const posts = await getPosts(1, 10);

return (

最新文章

    {posts.map((post: any) => (

  • {post.title.rendered}

  • ))}

);

}

文章详情页 - 动态路由 + ISR

// app/posts/[slug]/page.tsx

import { getPost, getPosts } from '@/lib/wp-api';

import { notFound } from 'next/navigation';

// 生成静态路径(构建时)

export async function generateStaticParams() {

const posts = await getPosts(1, 100); // 最多100篇

return posts.map((post: any) => ({

slug: post.slug,

}));

}

// ISR 配置:300秒重新验证

export const revalidate = 300;

export default async function PostPage({ params }: { params: { slug: string } }) {

const post = await getPost(params.slug);

if (!post) {

notFound();

}

return (

{post.title.rendered}

);

}

分类页 - 按需生成(On-Demand ISR)

// app/category/[slug]/page.tsx

import { getCategories, getPosts } from '@/lib/wp-api';

export const revalidate = 600; // 10分钟重新验证

export async function generateStaticParams() {

const categories = await getCategories();

return categories.map((cat: any) => ({

slug: cat.slug,

}));

}

export default async function CategoryPage({ params }: { params: { slug: string } }) {

// 获取该分类的文章

const posts = await getPosts(1, 10, params.slug);

return (

分类:{params.slug}

{/* 渲染文章列表 */}

);

}

实战三:按需重新验证(On-Demand Revalidation)

WordPress 端:发布文章时触发 Next.js 重新验证

// WordPress 主题 functions.php

add_action('publish_post', 'trigger_nextjs_revalidation');

function trigger_nextjs_revalidation($post_id) {

$secret = 'YOUR_REVALIDATE_SECRET'; // 与 Next.js 一致

$nextjs_url = 'https://your-nextjs-app.com';

// 触发首页重新验证

wp_remote_post($nextjs_url . '/api/revalidate', [

'headers' => [

'Content-Type' => 'application/json',

],

'body' => json_encode([

'secret' => $secret,

'path' => '/',

]),

]);

// 触发文章页重新验证

$post = get_post($post_id);

wp_remote_post($nextjs_url . '/api/revalidate', [

'body' => json_encode([

'secret' => $secret,

'path' => '/posts/' . $post->post_name,

]),

]);

}

Next.js 端:Revalidation API

// app/api/revalidate/route.ts

import { revalidatePath } from 'next/cache';

import { NextRequest, NextResponse } from 'next/server';

const SECRET = 'YOUR_REVALIDATE_SECRET';

export async function POST(request: NextRequest) {

const body = await request.json();

const { secret, path } = body;

// 验证 secret

if (secret !== SECRET) {

return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });

}

try {

// 重新验证指定路径

revalidatePath(path);

return NextResponse.json({ revalidated: true, path });

} catch (error) {

return NextResponse.json({ error: 'Failed to revalidate' }, { status: 500 });

}

}

实战四:预览模式(Draft Preview)

WordPress 端:预览链接

// WordPress 插件

add_filter('preview_post_link', 'custom_preview_link');

function custom_preview_link($link) {

$post = get_post();

$token = wp_generate_password(32, false);

// 保存 token(5分钟有效)

set_transient('preview_' . $token, $post->ID, 5 * MINUTE_IN_SECONDS);

// 生成 Next.js 预览链接

$nextjs_url = 'https://your-nextjs-app.com';

return $nextjs_url . '/api/preview?token=' . $token . '&post_id=' . $post->ID;

}

Next.js 端:预览模式 API

// app/api/preview/route.ts

import { draftMode } from 'next/headers';

import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {

const { searchParams } = new URL(request.url);

const token = searchParams.get('token');

const postId = searchParams.get('post_id');

// 验证 token(从 WordPress 获取)

const wpResponse = await fetch(

`https://www.shenma98.com/wp-json/wp/v2/posts/${postId}?preview=true`,

{

headers: {

'Authorization': 'Basic ' + btoa('username:app_password'),

'X-WP-Nonce': token, // 简化示例,实际需更安全

},

}

);

if (!wpResponse.ok) {

return NextResponse.json({ error: 'Invalid token' }, { status: 401 });

}

const post = await wpResponse.json();

// 启用草稿模式

draftMode().enable();

// 重定向到文章页

return NextResponse.redirect(new URL(`/posts/${post.slug}`, request.url));

}

性能优化

优化一:图片优化(Next.js Image 组件)

// 使用 Next.js Image 组件(自动 WebP/AVIF 转换)

import Image from 'next/image';

export default async function PostPage({ params }: { params: { slug: string } }) {

const post = await getPost(params.slug);

const featuredImage = post._embedded?.['wp:featuredmedia']?.[0];

return (

{featuredImage && (

src={featuredImage.source_url}

alt={featuredImage.alt_text}

width={1200}

height={630}

quality={85}

/>

)}

{/* 内容 */}

);

}

优化二:分页加载(Infinite Scroll)

// app/posts/page.tsx

'use client';

import { useState, useEffect } from 'react';

import { getPosts } from '@/lib/wp-api';

export default function PostsPage() {

const [posts, setPosts] = useState([]);

const [page, setPage] = useState(1);

const [loading, setLoading] = useState(false);

const loadMore = async () => {

setLoading(true);

const newPosts = await getPosts(page + 1, 10);

setPosts([...posts, ...newPosts]);

setPage(page + 1);

setLoading(false);

};

// 初始加载

useEffect(() => {

getPosts(1, 10).then(setPosts);

}, []);

return (

    {posts.map((post: any) => (

  • {post.title.rendered}
  • ))}

);

}

部署到 Vercel(推荐)

# 1. 推送到 GitHub

git init

git add .

git commit -m "Initial commit"

git remote add origin https://github.com/yourname/wp-nextjs.git

git push -u origin main

2. 导入到 Vercel

访问 vercel.com → Import Project → 选择 GitHub 仓库

设置环境变量:

NEXT_PUBLIC_WP_API_URL=https://www.shenma98.com/wp-json/wp/v2

3. 部署

Vercel 自动构建并部署

每次 git push → 自动重新部署

决策建议

| 场景 | 是否使用 Next.js + WordPress | 理由 |

|------|------------------------------|------|

| 内容型网站(博客/新闻) | ✅ 强烈推荐 | ISR 性能极致 |

| 高流量电商 | ✅ 推荐 | CDN 缓存 + ISR |

| 简单企业官网 | ❌ 不推荐 | WordPress 主题即可 |

| 需要复杂交互的 Web 应用 | ✅ 推荐 | Next.js 生态强 |

总结

Next.js 15 App Router + WordPress REST API + ISR 是 2026 年最流行的前后端分离方案。ISR 让静态站点拥有动态内容更新能力,性能与灵活性兼得。

立即行动:用 `create-next-app` 创建一个 Next.js 项目,然后连接你的 WordPress 站点!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。