Міграція сайту з WordPress на Headless CMS
Міграція з WordPress на headless CMS — це не просто зміна платформи. Це перегляд архітектури: відділення сховища контенту від фронтенду, зміна робочого процесу редакторів, інший розгортання. Потребує планування, поетапного виконання та періоду паралельної роботи.
Оцінка перед початком
Перед вибором цільової CMS потрібно відповісти:
- Скільки типів контенту (Custom Post Types) і полів (ACF)?
- Чи використовуються плагіни з власною логікою (WooCommerce, Events Calendar)?
- Який рівень технічної компетенції має команда контенту?
- Який бюджет на ліцензії (Contentful, Sanity) проти self-hosted?
- Чи потрібна підтримка чернеток та попередпродиску в новій CMS?
Порівняння цільових платформ
| Критерій | Contentful | Sanity | Strapi | KeystoneJS |
|---|---|---|---|---|
| Хостинг | SaaS | SaaS/Self | Self | Self |
| Ліцензія | Від $300/мес | Від $15/мес | Open Source | Open Source |
| Редактор | Хороший | Відмінний | Базовий | Базовий |
| API | REST + GraphQL | GROQ + GraphQL | REST + GraphQL | GraphQL |
| Медіа | CDN включений | CDN включений | Власне сховище | Власне |
Етап 1: Аудит контенту та маппінг (1–2 тижні)
Інвентаризація існуючого контенту:
# Експорт з WordPress через WP-CLI
wp export --post_type=post,page,product --status=publish --path=/var/www/html
# Аналіз ACF-полів
wp acf field-group export --group_id=all --output=json > acf-fields.json
# Статистика за типами
wp post list --post_type=post --format=count
wp post list --post_type=page --format=count
Маппінг WordPress → цільова CMS:
# mapping.yaml
wordpress_types:
post:
target: blogPost
fields:
post_title: title
post_content: body (RichText)
post_excerpt: excerpt
post_date: publishedAt
_thumbnail_id: featuredImage (Asset)
categories: categories (Reference[])
tags: tags (Reference[])
acf.seo_title: seoTitle
acf.seo_description: seoDescription
product:
target: product
fields:
post_title: name
_regular_price: price (Number)
_stock_qty: stock (Number)
product_cat: categories
acf.gallery: gallery (Asset[])
Етап 2: Настройка нової CMS (1 тиждень)
Створіть типи контенту в цільовій CMS точно за маппінгом. Налаштуйте валідації, локалізацію, ролі.
Етап 3: Скрипт міграції (1–2 тижні)
// scripts/migrate-from-wp.ts
import axios from 'axios';
import * as contentful from 'contentful-management';
import TurndownService from 'turndown';
const turndown = new TurndownService({ headingStyle: 'atx' });
const cmaClient = contentful.createClient({ accessToken: process.env.CMA_TOKEN! });
async function migratePosts() {
const space = await cmaClient.getSpace(process.env.SPACE_ID!);
const env = await space.getEnvironment('master');
// Отримуємо дописи з WP REST API
let page = 1;
while (true) {
const { data: posts } = await axios.get(
`${WP_URL}/wp-json/wp/v2/posts?per_page=100&page=${page}&_embed`
);
if (!posts.length) break;
for (const wpPost of posts) {
await migratePost(env, wpPost);
await delay(200); // Rate limiting
}
page++;
}
}
async function migratePost(env: any, wpPost: any) {
const featuredImageUrl = wpPost._embedded?.['wp:featuredmedia']?.[0]?.source_url;
let imageAsset;
if (featuredImageUrl) {
imageAsset = await uploadAsset(env, featuredImageUrl, wpPost.title.rendered);
}
const entry = await env.createEntry('blogPost', {
fields: {
title: { 'en-US': wpPost.title.rendered },
slug: { 'en-US': wpPost.slug },
body: { 'en-US': turndown.turndown(wpPost.content.rendered) },
excerpt: { 'en-US': wpPost.excerpt.rendered.replace(/<[^>]*>/g, '') },
publishedAt: { 'en-US': wpPost.date },
...(imageAsset && {
featuredImage: { 'en-US': { sys: { type: 'Link', linkType: 'Asset', id: imageAsset.sys.id } } },
}),
},
});
await entry.publish();
console.log(`Мігровано: ${wpPost.title.rendered}`);
}
Етап 4: Міграція медіафайлів
// Скачуємо та завантажуємо всі медіафайли WP
async function migrateMedia() {
const { data: media } = await axios.get(`${WP_URL}/wp-json/wp/v2/media?per_page=100`);
for (const item of media) {
const asset = await env.createAsset({
fields: {
title: { 'en-US': item.title.rendered },
description: { 'en-US': item.alt_text },
file: { 'en-US': {
contentType: item.mime_type,
fileName: path.basename(item.source_url),
upload: item.source_url,
}},
},
});
await asset.processForAllLocales();
await asset.publish();
mediaIdMap[item.id] = asset.sys.id; // для посилань
}
}
Етап 5: Паралельний запуск і перемикання
- Запустіть новий фронтенд на staging з реальними даними
- Проведіть дизайн-ревю з командою контенту
- Встановіть автоматичну синхронізацію WordPress → нова CMS на період переходу
- DNS-перемикання у період низького трафіку
- Відключіть WordPress через 2–4 тижні після стабілізації
Типова часова шкала міграції
| Етап | Малий сайт (<500 записів) | Середній (500–5000) | Великий (5000+) |
|---|---|---|---|
| Аудит та маппінг | 1 тиждень | 1–2 тижні | 2–4 тижні |
| Настройка CMS | 3–5 днів | 1 тиждень | 1–2 тижні |
| Скрипт міграції | 1 тиждень | 1–2 тижні | 2–4 тижні |
| Тестування | 3–5 днів | 1 тиждень | 2 тижні |
| Запуск | 1 день | 1–2 дні | 1 тиждень |
| Всього | 4–6 тижнів | 6–10 тижнів | 3–5 місяців |







