本文详解如何使用 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 (
最新文章
);
}
文章详情页 - 动态路由 + 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 (
{loading ? '加载中...' : '加载更多'}
);
}
部署到 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 站点!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论(0)