WordPress to Payload CMS migration plugin - Migrate posts, media, and content from WordPress to Payload CMS
npm install @teagantb/payload-wordpress-migrationA comprehensive plugin for migrating content from WordPress to Payload CMS. This plugin enables seamless migration of posts, media, categories, authors, and SEO metadata from WordPress to Payload CMS.
- 📝 Post Migration: Migrate WordPress posts with full content preservation
- 🖼️ Media Handling: Automatic image download and upload to Payload media collection
- 🏷️ Categories & Authors: Automatic creation of categories and authors/users
- 🌐 Multi-locale Support: Detect and migrate content in multiple languages (en/vi)
- 🔍 SEO Migration: Preserve SEO metadata from Rank Math and Yoast SEO
- 🎨 Block Conversion: Convert WordPress blocks to Lexical editor or CMS blocks
- 📊 Admin UI: User-friendly interface for migration management
- 🔄 Batch Processing: Process multiple posts in batches
``bash`
npm install @teagantb/payload-wordpress-migrationor
pnpm add @teagantb/payload-wordpress-migrationor
yarn add @teagantb/payload-wordpress-migration
`typescript
import { wordpressMigration } from '@teagantb/payload-wordpress-migration'
import { buildConfig } from 'payload'
export default buildConfig({
plugins: [
wordpressMigration({
collections: {
posts: 'posts',
categories: 'categories',
media: 'media',
users: 'users',
},
enableAdminUI: true,
adminRoute: '/migrate-xml',
}),
],
// ... rest of config
})
`
Your Payload config should have these collections:
- posts: With title, slug, content (richText), category, authors, heroImage, meta fieldstitle
- categories: With , slug fields
- media: With upload configuration
- users: With auth enabled
1. Start your Payload server: pnpm dev/admin/migrate-xml
2. Navigate to in your browser
3. Upload WordPress XML export file
4. Configure migration options
5. Click "Start Migration"
`typescript
interface WordPressMigrationPluginOptions {
/* Block type mappings (WordPress → Payload CMS) /
blockMappings?: {
youtube?: string
video?: string
videopress?: string
gallery?: string
button?: string
media?: string
banner?: string
columns?: string
}
/* Collection name mappings /
collections?: {
posts?: string
categories?: string
media?: string
users?: string
}
/* Enable admin UI (default: true) /
enableAdminUI?: boolean
/* Admin UI route path (default: '/migrate-xml') /
adminRoute?: string
}
`
`typescript
import { migrate } from '@teagantb/payload-wordpress-migration'
import { getPayload } from 'payload'
import config from '@payload-config'
const payload = await getPayload({ config })
const stats = await migrate(payload, {
xmlFilePath: './wordpress-export.xml',
batchSize: 10,
skipImages: false,
continueOnError: true,
})
console.log(Migrated ${stats.successfulPosts}/${stats.totalPosts} posts)`
`typescript`
const stats = await migrate(payload, {
wpApiUrl: 'https://example.com/wp-json/wp/v2',
wpCredentials: {
username: 'user',
password: 'app-password',
},
batchSize: 10,
})
`typescript`
const stats = await migrate(payload, {
useMock: true,
batchSize: 5,
})
`typescript
interface MigrationOptions {
/* Use mock data instead of fetching from WordPress /
useMock?: boolean
/* WordPress API endpoint /
wpApiUrl?: string
/* WordPress API credentials /
wpCredentials?: {
username: string
password: string
}
/* Path to WordPress XML export file /
xmlFilePath?: string
/* XML content as string (Cloudflare Workers compatible) /
xmlContent?: string
/* Batch size for processing posts /
batchSize?: number
/* Dry run (don't actually create posts) /
dryRun?: boolean
/* Skip image uploads /
skipImages?: boolean
/* Continue on errors /
continueOnError?: boolean
}
`
The plugin automatically converts WordPress blocks:
- Paragraphs
- Headings
- Lists
- Quotes
- Tables
- Code blocks
- Gallery → galleryBlockyoutubeBlock
- YouTube → videoBlock
- Video → videopressBlock
- VideoPress → buttonBlock
- Buttons → columnsBlock
- Columns →
You need to define these blocks in your Payload config. Block slugs can be customized via blockMappings option.
- ✅ WordPress Block Editor (Gutenberg)
- ✅ Classic Editor HTML
- ✅ Featured Images
- ✅ Categories and Tags
- ✅ Authors
- ✅ SEO Metadata (Rank Math, Yoast SEO)
- ✅ Multi-language (WPML, Polylang detection)
- ✅ Media attachments
After migration, you'll receive statistics:
`typescript`
interface MigrationStats {
totalPosts: number
successfulPosts: number
failedPosts: number
totalChunks: number
totalImages: number
totalErrors: number
processingTime: number // milliseconds
}
- Payload CMS 3.37.0 or higher
- Node.js 18.20.2 or higher
- Required collections: posts, categories, media, users
`bashInstall dependencies
pnpm install
MIT
For issues and questions, please open an issue on GitHub.