WordPress 迁移至 Next.js:完整技术指南
总结
从WordPress迁移到Next.js(2026年)会带来可衡量的性能提升:平均TTFB从1,200ms下降到85ms,页面权重从3.2 MB缩小到620 KB,Lighthouse评分从42跃升到94。该过程涉及通过WP REST API将内容导出到Supabase或Payload CMS、将媒体迁移到对象存储、为所有URL映射301重定向、在Next.js Metadata API中保留Yoast/RankMath SEO数据,以及用Server Actions替换Gravity Forms等插件。对于WooCommerce网站,Stripe替代了整个商务栈。预计典型网站(100-500页)需要4-8周,最大的时间投入在于重定向测试和模板重建。
这不是一个夸大其词的观点。我从事WordPress开发已有12年多。我已发布过代理商网站、会员平台、月收入六位数的WooCommerce商店以及无数自定义文章类型的网站。我也已将生产网站迁移到Next.js + Supabase。以下是每个技术细节——哪些能平稳映射,哪些不能,以及需要什么规划。
我不会假装WordPress很差。它不差。它为43%的网络提供支持是有充分理由的。但对于某些项目——性能是业务指标的网站、安全表面积很重要的网站、你想拥有部署管道的网站——Next.js是更好的工具。但是迁移?如果计划不周,这是个地雷阵。
本指南涵盖我使用的确切流程,包含真实代码、真实陷阱以及对你将获得和失去的内容的诚实评估。
目录
- 内容迁移:WP REST API到Supabase或Payload CMS
- 媒体迁移:从wp-content到Supabase Storage
- URL结构:映射每个旧URL
- SEO迁移:Yoast和RankMath数据到Next.js Metadata
- 表单:Gravity Forms到Server Actions
- WooCommerce到Stripe
- 迁移后监控
- 何时保留WordPress
- 性能基准:迁移前后
- 常见问题

内容迁移:WP REST API到Supabase或Payload CMS
每个WordPress迁移都从这里开始。你有文章、页面、自定义文章类型、ACF字段、分类法——多年的内容需要安全地存放在某处。
该内容的去向有两个不错的选择:
- Supabase ——如果你想要一个完全可控的数据库,具有行级安全和开箱即用的REST/GraphQL API
- Payload CMS ——如果你的客户需要一个在WordPress之后感觉熟悉的可视化编辑体验
对于我们的无头CMS开发项目,我们根据具体客户进行评估。编辑需要自助服务时选择Payload。开发人员是主要内容管理者或需要数据用于网站以外的用途时选择Supabase。
从WordPress迁移到Next.js时应该保留哪些内容结构?
迁移期间保留文章元数据、分类法、自定义字段和URL slug。你的WordPress文章包含多年的结构化数据:分类、标签、ACF字段、特色图片和发布日期。通过WP REST API使用_embed参数导出所有这些,在单个请求中获取媒体URL。存储内容的HTML和Markdown两个版本——HTML作为后备,Markdown用于MDX渲染。将自定义文章类型映射到新系统中的等效数据库表或CMS集合。
导出脚本
以下是我用来从WP REST API拉取内容、清理并将其插入到Supabase的Node.js脚本。这处理文章,但你会为页面和CPT复制该模式(只需更改端点)。
import { createClient } from '@supabase/supabase-js';
import TurndownService from 'turndown';
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SERVICE_KEY
);
const turndown = new TurndownService({
headingStyle: 'atx',
codeBlockStyle: 'fenced',
});
const WP_API = 'https://yoursite.com/wp-json/wp/v2';
async function fetchAllPosts() {
let page = 1;
let allPosts = [];
let hasMore = true;
while (hasMore) {
const res = await fetch(
`${WP_API}/posts?per_page=100&page=${page}&_embed`
);
if (!res.ok) break;
const posts = await res.json();
allPosts = allPosts.concat(posts);
const totalPages = parseInt(res.headers.get('X-WP-TotalPages'));
hasMore = page < totalPages;
page++;
}
return allPosts;
}
async function migrateContent() {
const posts = await fetchAllPosts();
console.log(`Fetched ${posts.length} posts from WordPress`);
const transformed = posts.map((post) => ({
wp_id: post.id,
title: post.title.rendered,
slug: post.slug,
content_html: post.content.rendered,
content_markdown: turndown.turndown(post.content.rendered),
excerpt: post.excerpt.rendered.replace(/<[^>]*>/g, '').trim(),
published_at: post.date,
status: post.status,
featured_image:
post._embedded?.['wp:featuredmedia']?.[0]?.source_url || null,
categories:
post._embedded?.['wp:term']?.[0]?.map((t) => t.name) || [],
tags:
post._embedded?.['wp:term']?.[1]?.map((t) => t.name) || [],
}));
const { data, error } = await supabase
.from('posts')
.upsert(transformed, { onConflict: 'wp_id' });
if (error) {
console.error('Migration failed:', error);
} else {
console.log(`Migrated ${transformed.length} posts to Supabase`);
}
}
migrateContent();
我艰难学到的几件事:
- 始终在WP REST API调用中使用
_embed。没有它,你获得的是媒体ID而不是URL,这意味着需要N+1个请求来解析特色图片。 - Turndown将HTML转换为Markdown ——如果你计划稍后使用MDX进行渲染,这至关重要。也保留原始HTML作为后备。
- 短代码不会保存。 WordPress通过REST API渲染某些短代码,但许多(特别是来自WPBakery或Elementor等插件的)会以原始括号文本形式出现。你需要一个短代码到组件的映射策略。我保留一个电子表格。
- ACF/自定义字段:如果使用ACF,你需要启用ACF to REST API插件,然后自定义字段会以每个文章对象的
acf属性形式出现。
Supabase表架构
CREATE TABLE posts (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
wp_id INTEGER UNIQUE,
title TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
content_html TEXT,
content_markdown TEXT,
excerpt TEXT,
published_at TIMESTAMPTZ,
status TEXT DEFAULT 'publish',
featured_image TEXT,
categories TEXT[],
tags TEXT[],
seo_title TEXT,
seo_description TEXT,
og_image TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
注意我包含了seo_title、seo_description和og_image列。你在下方SEO迁移部分需要这些。
媒体迁移:从wp-content到Supabase Storage
这是大多数指南都掠过的部分,也是耗时最长的部分。一个12年老的WordPress网站轻易可能在wp-content/uploads/中有10,000+个文件。
该方法:
- 下载整个
wp-content/uploads/目录 - 上传到Supabase Storage(或Cloudflare R2或S3)
- 重写内容中的每个媒体URL
如何将WordPress媒体文件迁移到现代对象存储?
下载整个wp-content/uploads/目录,上传到Supabase Storage或Cloudflare R2,然后重写内容中的所有媒体URL。使用脚本从你的WordPress内容中获取每个图像URL,上传到对象存储并保留目录结构(2024/03/image.jpg),然后运行第二轮以用新存储URL替换旧URL。为直接链接到你旧图像URL的外部网站设置通配符重定向。
下载和上传脚本
import { createClient } from '@supabase/supabase-js';
import fs from 'fs';
import path from 'path';
import fetch from 'node-fetch';
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SERVICE_KEY
);
const BUCKET = 'media';
async function migrateMedia(posts) {
const urlRegex =
/https?:\/\/yoursite\.com\/wp-content\/uploads\/[^\s"')]+/g;
for (const post of posts) {
const urls = post.content_html.match(urlRegex) || [];
for (const url of urls) {
try {
const res = await fetch(url);
const buffer = Buffer.from(await res.arrayBuffer());
// Preserve directory structure: 2024/03/image.jpg
const storagePath = url.replace(
/https?:\/\/yoursite\.com\/wp-content\/uploads\//,
''
);
const { error } = await supabase.storage
.from(BUCKET)
.upload(storagePath, buffer, {
contentType: res.headers.get('content-type'),
upsert: true,
});
if (error) console.error(`Failed: ${storagePath}`, error);
else console.log(`Uploaded: ${storagePath}`);
} catch (e) {
console.error(`Skipped: ${url}`, e.message);
}
}
}
}
async function rewriteUrls() {
const { data: posts } = await supabase.from('posts').select('*');
const supabaseBase = `${process.env.SUPABASE_URL}/storage/v1/object/public/${BUCKET}`;
for (const post of posts) {
const updated = post.content_html.replace(
/https?:\/\/yoursite\.com\/wp-content\/uploads\//g,
`${supabaseBase}/`
);
await supabase
.from('posts')
.update({
content_html: updated,
content_markdown: turndown.turndown(updated),
})
.eq('id', post.id);
}
}
图像性能收益
这是迁移真正带来回报的地方。WordPress提供原始上传——通常是人们从数码单反相机上传的3000×2000px PNG。即使有ShortPixel这样的插件,你仍然通过PHP提供图像。
Next.js<Image>组件与next/image进行自动格式协商(WebP/AVIF)、响应式尺寸调整和懒加载。我们上次迁移的数字:
| 指标 | WordPress | Next.js + Image组件 |
|---|---|---|
| 平均页面图像权重 | 2.1 MB | 380 KB |
| 图像请求 | 每页12个 | 6个(懒加载) |
| 格式 | JPEG/PNG | WebP(支持AVIF) |
| 累积布局偏移 | 0.18 | 0.02 |
那不是打字错误。平均图像载荷从2.1 MB下降到380 KB。 这是在没有重新上传优化文件的情况下——只是让next/image完成工作。
import Image from 'next/image';
export function PostImage({ src, alt }: { src: string; alt: string }) {
return (
<Image
src={src}
alt={alt}
width={800}
height={450}
sizes="(max-width: 768px) 100vw, 800px"
quality={80}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..." // 在构建时生成
/>
);
}
URL结构:映射每个旧URL
这是迁移失败的地方。一个遗漏的重定向意味着一个页面的404,而Google已为其编制索引多年。我以与数据库迁移相同的认真度处理URL映射——测试它、验证它,然后再次验证。
在WordPress迁移期间处理URL重定向的正确方法是什么?
从WordPress导出每个已发布的URL,与Google Search Console索引的URL进行交叉引用,然后对所有URL实施301重定向。查询你的wp_posts表以获取所有已发布的URL,导出GSC的索引URL,然后创建一个重定向映射。对于少于50个URL使用next.config.js重定向,对于50-1,024个URL使用JSON文件,或对于超过Vercel 1,024重定向限制的网站使用中间件。包括针对分类页面、分页和wp-content/uploads路径的通配符重定向。
映射过程
首先,从WordPress导出每个URL。我直接从数据库拉取:
SELECT
CONCAT('/', post_name, '/') AS old_url,
post_type,
post_status
FROM wp_posts
WHERE post_status = 'publish'
AND post_type IN ('post', 'page', 'product')
ORDER BY post_type, post_name;
然后与Google Search Console的索引URL进行交叉引用。GSC经常显示你的数据库中不存在的URL——旧分类页面、分页URL、附件页面。你需要对所有这些进行重定向。
next.config.js重定向
对于少于50个重定向的网站,内联它们:
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/2019/03/old-post-slug/',
destination: '/blog/old-post-slug',
permanent: true,
},
{
source: '/category/:slug',
destination: '/blog/category/:slug',
permanent: true,
},
{
source: '/product/:slug',
destination: '/shop/:slug',
permanent: true,
},
];
},
};
对于200+个重定向:使用JSON文件
一旦超过几百个,维护内联重定向会很痛苦。我使用JSON文件:
// redirects.json
[
{
"source": "/2018/01/my-old-post/",
"destination": "/blog/my-old-post",
"permanent": true
},
{
"source": "/about-us/",
"destination": "/about",
"permanent": true
},
{
"source": "/wp-content/uploads/:path*",
"destination": "https://yourbucket.supabase.co/storage/v1/object/public/media/:path*",
"permanent": true
}
]
// next.config.js
const redirectsList = require('./redirects.json');
module.exports = {
async redirects() {
return redirectsList;
},
};
wp-content/uploads的通配符重定向至关重要。会有外部网站直接链接到你的图像。不要失去这些反向链接。
重要:Vercel在next.config.js中有1,024个重定向的限制。对于超过该限制的网站,使用中间件:
// middleware.ts
import { NextResponse } from 'next/server';
import redirects from './redirects.json';
const redirectMap = new Map(
redirects.map((r) => [r.source, r])
);
export function middleware(request) {
const redirect = redirectMap.get(request.nextUrl.pathname);
if (redirect) {
return NextResponse.redirect(
new URL(redirect.destination, request.url),
redirect.permanent ? 308 : 307
);
}
}

SEO迁移:Yoast和RankMath数据到Next.js Metadata
如果你一直在使用Yoast或RankMath,你有多年的自定义元标题、描述和Open Graph数据存储在wp_postmeta表中。不要丢失它。
迁移到Next.js时如何保留Yoast SEO数据?
从wp_postmeta导出Yoast元标题、描述和Open Graph图像,将它们存储在新数据库中,然后使用Next.js Metadata API渲染它们。查询wp_postmeta以获取_yoast_wpseo_title、_yoast_wpseo_metadesc和_yoast_wpseo_opengraph-image字段。将此数据导入到你的文章表中的专用SEO列。使用Next.js App Router中的generateMetadata将此数据呈现为正确的元标签和Open Graph标记。
导出SEO数据
SELECT
p.post_name AS slug,
MAX(CASE WHEN pm.meta_key = '_yoast_wpseo_title' THEN pm.meta_value END) AS seo_title,
MAX(CASE WHEN pm.meta_key = '_yoast_wpseo_metadesc' THEN pm.meta_value END) AS seo_description,
MAX(CASE WHEN pm.meta_key = '_yoast_wpseo_opengraph-image' THEN pm.meta_value END) AS og_image
FROM wp_posts p
JOIN wp_postmeta pm ON p.ID = pm.post_id
WHERE p.post_status = 'publish'
GROUP BY p.ID, p.post_name;
对于RankMath,交换元键:rank_math_title、rank_math_description、rank_math_facebook_image。
将此数据导入到你的Supabaseposts表中我们之前定义的SEO列。
Next.js Metadata API
对于App Router,元数据是一流的:
// app/blog/[slug]/page.tsx
import { supabase } from '@/lib/supabase';
import { Metadata } from 'next';
export async function generateMetadata(
{ params }: { params: { slug: string } }
): Promise<Metadata> {
const { data: post } = await supabase
.from('posts')
.select('title, seo_title, seo_description, og_image')
.eq('slug', params.slug)
.single();
return {
title: post.seo_title || post.title,
description: post.seo_description,
openGraph: {
title: post.seo_title || post.title,
description: post.seo_description,
images: post.og_image ? [{ url: post.og_image }] : [],
},
};
}
作为JSON-LD的架构标记服务器组件
WordPress插件自动生成架构。在Next.js中,你自己构建——这实际上给你更多的控制权:
// components/ArticleSchema.tsx
export function ArticleSchema({ post }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
datePublished: post.published_at,
dateModified: post.updated_at || post.published_at,
author: {
'@type': 'Organization',
name: 'Your Company',
},
image: post.og_image,
description: post.seo_description,
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
动态网站地图
// app/sitemap.ts
import { supabase } from '@/lib/supabase';
export default async function sitemap() {
const { data: posts } = await supabase
.from('posts')
.select('slug, published_at')
.eq('status', 'publish');
return posts.map((post) => ({
url: `https://yoursite.com/blog/${post.slug}`,
lastModified: post.published_at,
changeFrequency: 'monthly',
priority: 0.8,
}));
}
这在构建时为静态网站生成或按需为动态网站生成。没有插件、没有XML模板文件、没有缓存问题。
表单:Gravity Forms到Server Actions
Gravity Forms是有史以来最好的WordPress插件之一。它也是每年$259的Elite许可证,每个表单加载200KB+的JavaScript。
以下是替代方案。每个表单大约20行代码。
导出现有条目
首先,从WordPress管理员导出你的Gravity Forms条目为CSV。如果需要,将其存储在Supabase中用于历史记录。
Server Action联系表单
// app/contact/page.tsx
export default function ContactPage() {
async function submitForm(formData: FormData) {
'use server';
const { createClient } = await import('@supabase/supabase-js');
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_KEY!
);
const entry = {
name: formData.get('name') as string,
email: formData.get('email') as string,
message: formData.get('message') as string,
submitted_at: new Date().toISOString(),
};
// Validate
if (!entry.name || !entry.email || !entry.message) {
throw new Error('All fields required');
}
await supabase.from('form_submissions').insert(entry);
// Optional: send notification email via Resend
await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'forms@yoursite.com',
to: 'team@yoursite.com',
subject: `New contact: ${entry.name}`,
html: `<p>${entry.message}</p><p>From: ${entry.email}</p>`,
}),
});
}
return (
<form action={submitForm}>
<input name="name" type="text" required placeholder="Name" />
<input name="email" type="email" required placeholder="Email" />
<textarea name="message" required placeholder="Message" />
<button type="submit">Send</button>
</form>
);
}
没有插件。表单本身没有JavaScript载荷(它是带有server action的本地HTML表单)。渐进式增强——即使在禁用JavaScript的情况下也能工作。
对于更复杂的表单(多步骤、文件上传、条件字段),我们在客户端使用React Hook Form与相同的server action模式。关键的认识:当你有数据库和API时,你不需要表单插件。
WooCommerce到Stripe
这是任何WordPress迁移中最难的部分。WooCommerce不仅仅是一个插件——它是一个有产品、变体、库存、订单、订阅、优惠券、税收和运费规则的商务平台。你不是在迁移功能。你是在替换平台。
如何将WooCommerce产品迁移到Stripe?
通过WooCommerce REST API或CSV导出产品,然后使用Stripe Products API在Stripe中创建匹配的产品,价格。对于500个产品以下的网站,直接推送到Stripe使用他们的API:创建包含名称、描述和图像的产品,然后创建链接到该产品的价格对象。在Stripe元数据中存储WooCommerce产品ID作为参考。使用Stripe Checkout Sessions进行支付处理和webhooks以在你的数据库中跟踪订单。
产品迁移
通过CSV或REST API从WooCommerce导出产品。你有两个目标选项:
| 方法 | 适合 | 权衡 |
|---|---|---|
| Supabase产品表 | 自定义店面、复杂过滤 | 你管理库存逻辑 |
| Stripe Products API | 简单目录、订阅业务 | Stripe管理定价,你管理显示 |
对于大多数500个产品以下的网站,我直接推送到Stripe Products:
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
async function migrateProducts(wooProducts) {
for (const product of wooProducts) {
const stripeProduct = await stripe.products.create({
name: product.name,
description: product.short_description,
images: [product.images[0]?.src].filter(Boolean),
metadata: {
woo_id: String(product.id),
slug: product.slug,
sku: product.sku,
},
});
await stripe.prices.create({
product: stripeProduct.id,
unit_amount: Math.round(parseFloat(product.price) * 100),
currency: 'usd',
});
console.log(`Created: ${product.name} → ${stripeProduct.id}`);
}
}
使用Stripe Checkout Sessions的结账
// app/api/checkout/route.ts
import { NextResponse } from 'next/server';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(request: Request) {
const { priceId, quantity = 1 } = await request.json();
const session = await stripe.checkout.sessions.create({
mode: 'payment',
payment_method_types: ['card'],
line_items: [{ price: priceId, quantity }],
success_url: `${process.env.NEXT_PUBLIC_URL}/order/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/shop`,
});
return NextResponse.json({ url: session.url });
}
订阅
如果你在WooCommerce Subscriptions上($239/年),切换到Stripe Billing。将mode: 'payment'改为mode: 'subscription'并确保你的价格设置了recurring。就这样。Stripe处理试用期、按比例分配和催收。
通过Webhooks进行订单跟踪
// app/api/webhooks/stripe/route.ts
import { headers } from 'next/headers';
import Stripe from 'stripe';
import { supabase } from '@/lib/supabase';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(request: Request) {
const body = await request.text();
const sig = headers().get('stripe-signature')!;
const event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!
);
if (event.type === 'checkout.session.completed') {
const session = event.data.object as Stripe.Checkout.Session;
await supabase.from('orders').insert({
stripe_session_id: session.id,
customer_email: session.customer_details?.email,
amount_total: session.amount_total,
status: 'completed',
});
}
return new Response('OK', { status: 200 });
}
Stripe的交易费为2.9% + $0.30每笔交易。与WooCommerce相比,你需要支付托管费用($30-100/月用于托管WP)、Subscriptions插件($239/年)、支付网关插件以及可能还有一些其他插件。数学运算快速得出结论。
对于复杂的商务迁移,我们将其作为Next.js开发服务的一部分提供——这是我们收到的最常见的请求之一。
迁移后监控
启动不是结束。迁移后的前两周是关键。
Google Search Console
- 立即提交你的新网站地图
- 使用URL Inspection工具请求索引你的前20个页面
- 第一周每天监控Coverage报告——关注404s的峰值
- 检查"页面索引"报告中任何卡在"已发现——目前未编制索引"的页面
分析比较
设置一个仪表板来逐周比较:
- 总会话
- 特别是有机搜索流量
- 按页面的跳出率
- 转换率(表单提交、购买)
第一周的小幅流量下降是正常的。如果到第三周还没有恢复,说明重定向或索引出了问题。
Lighthouse审计
在每个主要模板(主页、博客文章、产品页面、联系页面)上运行Lighthouse。目标:
- 性能:90+
- 可访问性:95+
- 最佳实践:95+
- SEO:100
在我们上次迁移——一个400页的内容网站——上,我们将WordPress上的平均Lighthouse性能评分从38提高到Vercel上Next.js的96。那不是樱桃精选。那是平均值。
何时保留WordPress
这是我失去一些人的部分,但这是本指南中最重要的部分。
如果出现以下情况,请不要迁移:
- 你有一个简单的博客或宣传册网站,不到20页
- 你的团队是非技术性的,依赖于WordPress管理员进行日常更新
- 你的Lighthouse评分已经是70+,没有性能关键的业务需求
- 你没有安全问题,托管是稳定的
- 你的总插件成本在$200/年以下
- 你没有开发人员(或预算)来维护Next.js网站
带有好主机(Cloudways、Kinsta)、可靠的主题和最少插件的WordPress很好。实际上,它超过了好——它经过战斗测试,文档齐全,被数百万开发人员理解。
迁移在以下情况下有意义:
- 性能与收入直接相关(电子商务、SaaS营销网站)
- 你在托管和安全插件上花费$500+/月
- 你的开发团队已经在写React
- 你需要一个部署管道,包括预览构建、暂存环境和回滚
- 安全表面积是一个真实的关切(政府、医疗、金融)
我这样说是因为信任比销售更重要。如果你不确定迁移是否值得,联系我们,我们会给你一个诚实的评估。
性能基准:迁移前后
来自我们在2024-2025年进行的最后五次迁移:
| 指标 | WordPress(平均) | Next.js(平均) | 变化 |
|---|---|---|---|
| TTFB | 1,200ms | 85ms | 快14倍 |
| LCP | 3.8s | 0.9s | 快4.2倍 |
| 总页面权重 | 3.2 MB | 620 KB | 轻5倍 |
| 每页请求 | 47 | 11 | 减少77% |
| Lighthouse性能 | 42 | 94 | +52点 |
| 月托管成本 | $75 | $20(Vercel Pro) | 节省73% |
| Core Web Vitals通过率 | 31%的页面 | 100%的页面 | ✓ |
这些是来自生产网站的真实数字。WordPress网站运行在托管主机(WP Engine和Kinsta)上,优化缓存和图像优化插件。它们没有被忽视——它们是已经达到WordPress可以提供的上限的维护网站。
如果你有兴趣了解现代框架可能发生什么,也可以看看我们的Astro开发能力——对于内容丰富、交互最少的网站,Astro甚至可以提供比Next.js更小的载荷。
常见问题
从WordPress迁移到Next.js需要多长时间?
对于一个有100-500页的典型网站,预计4-8周的开发时间。简单的宣传册网站可以在2-3周内完成。有数千种产品的复杂WooCommerce商店可能需要10-12周。内容迁移本身很快——重建前端模板和测试每个重定向才是耗时的。
从WordPress迁移到Next.js时会失去SEO排名吗?
不会,如果你正确处理重定向和元数据。关键部分是:每个旧URL的301重定向、迁移所有Yoast/RankMath元标题和描述、保留你的网站地图结构以及立即向Google Search Console提交新网站地图。我们看到网站在迁移后1-2周内恢复到迁移前的流量,由于改进的Core Web Vitals,在第三个月到达时有显著增长。
我可以将WordPress与Next.js作为无头CMS一起使用吗?
是的,这是一种流行的方法。你保留WordPress作为内容后端,使用WP REST API或WPGraphQL,而Next.js作为前端。这保留了熟悉的编辑体验,同时获得Next.js性能。缺点是你仍在维护一个WordPress安装,有其安全和更新开销。我们通常为新项目推荐Payload CMS或Sanity,除非团队深入投入于WordPress工作流。
从WordPress迁移到Next.js需要多少成本?
DIY与开发人员时间:工具中免费,但预算80-200小时的开发时间。机构成本:通常$10,000-$50,000,取决于网站复杂性、页面数量、电子商务功能和自定义功能。查看我们的定价页面以了解我们包裹的具体情况。ROI通常来自减少的托管成本($50-100/月的节省)、消除的插件许可费和更好的性能增加的转换率。
迁移后WordPress插件会发生什么?
每个插件需要一个Next.js等效项。Contact Form 7或Gravity Forms变成Server Action。Yoast SEO变成Next.js Metadata API。WooCommerce变成Stripe。Google Analytics保持不变(只需移动跟踪代码片段)。Wordfence之类的一些插件变得不必要,因为没有要攻击的WordPress。在开始前制作一个完整的插件清单——任何没有明确替换策略的插件都是一个风险。
我应该从WordPress迁移到Next.js还是Astro?
这取决于你的交互性需求。Next.js更适合具有动态功能的网站——用户身份验证、电子商务、仪表板、实时数据。Astro更适合内容丰富的网站,主要是静态的——博客、文档、营销网站。Astro默认不发送JavaScript,这意味着更小的页面大小。我们与两者都合作——查看我们的Astro开发和Next.js开发页面以了解详细信息。
我可以将WooCommerce订阅迁移到Stripe吗?
是的,但需要仔细处理活跃订户。你需要在Stripe中创建客户和订阅,然后向客户传达账单变化。Stripe Billing处理试用期、按比例分配、失败支付重试逻辑和取消流程。迁移本身是一个一次性脚本,但针对真实订阅情景的测试是耗时的地方。如果你有超过100个活跃订户,预算额外时间。
迁移WordPress之后Next.js的最佳托管是什么?
Vercel是默认选择——它由制作Next.js的团队构建,免费层处理大多数营销网站。Vercel Pro是$20/月的团队。替代选项包括Netlify、Cloudflare Pages(边缘性能优异)以及自托管,如果你想完全控制,可以在VPS上使用Docker。所有这些的成本与等效流量级别的托管WordPress托管相比都明显便宜。