跳到主要内容
稻草人
プロフィール

EP.02

💻Technology

WordPressとNext.jsを組み合わせるときの考え方

WordPressをCMSとして使い、Next.jsでフロントを作るときの設計ポイント。

BY 稻, 草人

WordPress负责内容管理,Next.js负责前端显示,这种Headless CMS结构听起来很合理。编辑者继续使用熟悉的后台,前端又能使用React、TypeScript和现代构建工具。

但我实际做WordPress项目后,越来越觉得:能不能实现不是最难的问题,真正难的是把预览、缓存、图片、表单、SEO和故障处理全部接起来。

所以在决定组合之前,我会先确认为什么要这样做。

目次

先问:普通WordPress哪里不够

如果只是企业介绍、博客和联系表单,主题开发已经能满足需求,那么拆成两个系统会增加成本:

  • WordPress和Next.js需要分别部署
  • 内容更新后要考虑缓存刷新
  • 预览需要额外实现
  • 插件产生的页面不一定能直接使用
  • 故障时要判断是CMS、API、构建还是前端的问题

Headless并不自动等于更快、更安全。它只是把职责重新分配。

比较适合的情况包括:

  • 同一份内容要提供给Web、App等多个客户端
  • 前端交互复杂,已经需要React生态
  • 团队希望完全控制路由和渲染方式
  • 内容模型较稳定,能够维护API契约

最基本的职责划分

WordPress负责:

  • 文章、分类、标签和媒体管理
  • 编辑权限与工作流
  • REST API或GraphQL输出

Next.js负责:

  • 页面路由与渲染
  • 前端组件
  • SEO标签
  • 图片显示
  • 缓存与再验证

先把边界写下来,后面遇到问题时才知道应该在哪一侧修改。

不要让WordPress原始结构遍布组件

type WpPost = {
  id: number
  slug: string
  title: { rendered: string }
  content: { rendered: string }
  excerpt: { rendered: string }
  date: string
}

建议在数据层转换成前端自己的模型:

type Article = {
  id: number
  slug: string
  titleHtml: string
  contentHtml: string
  excerptHtml: string
  publishedAt: string
}

function mapArticle(post: WpPost): Article {
  return {
    id: post.id,
    slug: post.slug,
    titleHtml: post.title.rendered,
    contentHtml: post.content.rendered,
    excerptHtml: post.excerpt.rendered,
    publishedAt: post.date
  }
}

这样以后更换API插件或字段结构时,影响主要集中在数据层。

渲染方式要按页面决定

不是整个网站只能选择一种方式。

  • 公司介绍等很少变化的页面:静态生成或长时间缓存
  • 博客文章:静态生成加按需再验证
  • 搜索结果:请求时获取或客户端查询
  • 登录后的个人信息:动态渲染

先根据更新频率、是否登录、是否需要实时性来决定,不要为了“全部SSR”或“全部静态”而勉强统一。

缓存刷新是核心问题

编辑者在WordPress点击更新后,Next.js页面什么时候变化?如果没有明确流程,编辑者会认为发布失败。

一种做法是:

  1. WordPress保存文章
  2. Webhook通知Next.js
  3. Next.js验证密钥
  4. 只刷新受影响的路径或标签
  5. 返回处理结果并记录日志

需要考虑Webhook重试、重复通知、密钥轮换和失败告警。不能只测试成功的一次。

草稿预览不能最后再做

公开REST API通常只能读取已发布内容。草稿预览需要:

  • WordPress端生成安全的预览入口
  • Next.js验证临时令牌或登录状态
  • 读取未发布内容
  • 进入预览模式,绕过公开缓存
  • 退出预览

如果编辑人员依赖预览,这就是首要功能,而不是上线前的附加项。

HTML内容与XSS

WordPress正文通常以HTML返回,在React中可能使用dangerouslySetInnerHTML。

<article dangerouslySetInnerHTML={{ __html: article.contentHtml }} />

这要求内容来源和权限边界可信,并确认WordPress端的HTML清理策略。不要把URL参数、外部API内容或用户输入混入后直接输出。

图片处理

要确认:

  • WordPress媒体URL是否允许被Next.js读取
  • 响应式尺寸是否正确
  • alt是否来自媒体信息或正文
  • 图片被替换后缓存如何更新
  • 删除媒体后旧页面会不会失效
  • 是否需要CDN

只把原图URL放进页面,可能造成流量和LCP问题。

SEO与站点地图

Headless以后,SEO责任基本转到Next.js。至少需要处理:

  • title和description
  • canonical
  • Open Graph
  • robots
  • sitemap
  • 结构化数据
  • 分类、标签、分页页面
  • 文章删除后的404或重定向

如果WordPress里的SEO插件产生了元数据,还要决定是否通过API读取并映射。

插件不能默认继续生效

联系表单、相关文章、目录、短代码、会员功能等插件,可能只在传统主题渲染时有效。

采用Headless前,要列出当前插件,分别判断:

  • 只影响后台
  • 能通过API继续使用
  • 需要在Next.js重新实现
  • 已经没有必要

这里往往是估算偏差最大的地方。

安全与运维

隐藏wp-admin不是主要安全措施。更重要的是:

  • WordPress、主题和插件及时更新
  • API只开放需要的数据
  • 限制跨域和写入接口
  • 保护Webhook与预览令牌
  • 配置备份与恢复
  • 记录两侧日志
  • 监控WordPress、API和Next.js部署

系统变成两部分后,也要准备“WordPress正常但Next.js失败”和“前端正常但CMS无法编辑”等场景。

我的判断标准

如果普通WordPress已经可以稳定完成需求,我不会只为了技术更新而Headless化。若项目确实需要复杂前端、多客户端复用或独立扩展,WordPress加Next.js才会有明显价值。

决定前,我会先做一个小型PoC,至少验证文章列表、详情、图片、预览、更新后的缓存刷新和404处理。只有这条链路完整跑通,才能比较准确地估算正式项目。

参考资料