payload-wordpress-migrator 0.0.22 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -422
- package/dist/components/FieldMappingConfiguration.js +2 -10
- package/dist/components/FieldMappingConfiguration.js.map +1 -1
- package/dist/components/MigrationDashboardClient.js +2 -8
- package/dist/components/MigrationDashboardClient.js.map +1 -1
- package/dist/components/SimpleFieldMapping.js +4 -13
- package/dist/components/SimpleFieldMapping.js.map +1 -1
- package/dist/components/dashboard/SiteConfigPanel.d.ts +3 -9
- package/dist/components/dashboard/SiteConfigPanel.js +60 -170
- package/dist/components/dashboard/SiteConfigPanel.js.map +1 -1
- package/dist/components/dashboard/index.d.ts +1 -1
- package/dist/components/dashboard/types.d.ts +0 -8
- package/dist/components/dashboard/useMigrationDashboard.d.ts +2 -8
- package/dist/components/dashboard/useMigrationDashboard.js +33 -195
- package/dist/components/dashboard/useMigrationDashboard.js.map +1 -1
- package/dist/utils/endpoints/handlers.js +29 -11
- package/dist/utils/endpoints/handlers.js.map +1 -1
- package/dist/utils/migration/jobCrud.js +4 -4
- package/dist/utils/migration/jobCrud.js.map +1 -1
- package/dist/utils/migration/orchestrator.d.ts +2 -2
- package/dist/utils/migration/orchestrator.js +5 -5
- package/dist/utils/migration/orchestrator.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,36 +1,26 @@
|
|
|
1
|
-
# Payload WordPress Migrator
|
|
1
|
+
# Payload WordPress Migrator
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A PayloadCMS plugin for migrating WordPress content — manage migrations directly from the Payload admin dashboard.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- 🔒 **Production Ready**: Comprehensive error handling and SSL certificate management
|
|
7
|
+
- **Migration Dashboard** — real-time progress tracking in the Payload admin UI
|
|
8
|
+
- **WordPress REST API Integration** — secure connectivity with Application Passwords
|
|
9
|
+
- **Job Management** — create, pause, resume, retry, rollback, and dry-run migration jobs
|
|
10
|
+
- **Content Type Discovery** — automatic detection of posts, pages, media, categories, tags, custom post types
|
|
11
|
+
- **Field Mapping** — visual mapping interface with dot-notation support
|
|
12
|
+
- **Media Migration** — auto-import featured images and content media with duplicate detection
|
|
13
|
+
- **Gutenberg to Lexical** — converts WordPress blocks to PayloadCMS Lexical rich text
|
|
14
|
+
- **Batch Processing** — configurable concurrency with background execution
|
|
15
|
+
- **Access Control** — configurable role-based access for migration endpoints
|
|
17
16
|
|
|
18
|
-
##
|
|
17
|
+
## Installation
|
|
19
18
|
|
|
20
19
|
```bash
|
|
21
|
-
# npm
|
|
22
20
|
npm install payload-wordpress-migrator
|
|
23
|
-
|
|
24
|
-
# yarn
|
|
25
|
-
yarn add payload-wordpress-migrator
|
|
26
|
-
|
|
27
|
-
# pnpm
|
|
28
|
-
pnpm add payload-wordpress-migrator
|
|
29
21
|
```
|
|
30
22
|
|
|
31
|
-
##
|
|
32
|
-
|
|
33
|
-
### Basic Setup
|
|
23
|
+
## Quick Start
|
|
34
24
|
|
|
35
25
|
Add the plugin to your Payload config:
|
|
36
26
|
|
|
@@ -39,12 +29,8 @@ import { buildConfig } from 'payload'
|
|
|
39
29
|
import { payloadWordPressMigrator } from 'payload-wordpress-migrator'
|
|
40
30
|
|
|
41
31
|
export default buildConfig({
|
|
42
|
-
// ... your existing config
|
|
43
32
|
plugins: [
|
|
44
33
|
payloadWordPressMigrator({
|
|
45
|
-
wpSiteUrl: process.env.WORDPRESS_API_URL,
|
|
46
|
-
wpUsername: process.env.WORDPRESS_USERNAME,
|
|
47
|
-
wpPassword: process.env.WORDPRESS_APP_PASSWORD,
|
|
48
34
|
collections: {
|
|
49
35
|
posts: { wpPostType: 'post', enableBlocks: true },
|
|
50
36
|
pages: { wpPostType: 'page', enableBlocks: true },
|
|
@@ -57,146 +43,110 @@ export default buildConfig({
|
|
|
57
43
|
})
|
|
58
44
|
```
|
|
59
45
|
|
|
60
|
-
### Environment Variables
|
|
61
|
-
|
|
62
|
-
Add these to your `.env` file:
|
|
63
|
-
|
|
64
|
-
```env
|
|
65
|
-
WORDPRESS_API_URL=https://your-wordpress-site.com
|
|
66
|
-
WORDPRESS_USERNAME=your-username
|
|
67
|
-
WORDPRESS_APP_PASSWORD=your-application-password
|
|
68
|
-
```
|
|
69
|
-
|
|
70
46
|
### WordPress Setup
|
|
71
47
|
|
|
72
|
-
|
|
48
|
+
**Application Password:**
|
|
73
49
|
|
|
74
|
-
1. In WordPress admin, go to **Users
|
|
75
|
-
2. Scroll
|
|
76
|
-
3. Enter a name (e.g., "Payload Migration")
|
|
77
|
-
4.
|
|
78
|
-
5. Copy the generated password (save it securely)
|
|
79
|
-
6. Use this password as `WORDPRESS_APP_PASSWORD`
|
|
50
|
+
1. In WordPress admin, go to **Users > Profile**
|
|
51
|
+
2. Scroll to **Application Passwords**
|
|
52
|
+
3. Enter a name (e.g., "Payload Migration") and click **Add New Application Password**
|
|
53
|
+
4. Copy the generated password — use this as `WORDPRESS_APP_PASSWORD`
|
|
80
54
|
|
|
81
|
-
|
|
55
|
+
**Requirements:**
|
|
82
56
|
|
|
83
57
|
- WordPress 5.6+ (for Application Passwords)
|
|
84
58
|
- REST API enabled (default in most installations)
|
|
85
59
|
- User with appropriate permissions for content access
|
|
86
60
|
|
|
87
|
-
|
|
61
|
+
## Configuration
|
|
88
62
|
|
|
89
63
|
```typescript
|
|
90
64
|
type PayloadWordPressMigratorConfig = {
|
|
91
65
|
// WordPress Connection
|
|
92
66
|
wpSiteUrl?: string // WordPress site URL
|
|
93
67
|
wpUsername?: string // WordPress username
|
|
94
|
-
wpPassword?: string //
|
|
68
|
+
wpPassword?: string // Application password (not the login password)
|
|
95
69
|
|
|
96
|
-
//
|
|
70
|
+
// Collections
|
|
97
71
|
collections?: Partial<Record<CollectionSlug, WordPressCollectionMapping>>
|
|
98
72
|
|
|
99
73
|
// Plugin Control
|
|
100
|
-
disabled?: boolean // Disable plugin
|
|
101
|
-
disableDashboard?: boolean //
|
|
74
|
+
disabled?: boolean // Disable plugin (schema still added for DB consistency)
|
|
75
|
+
disableDashboard?: boolean // Hide dashboard UI
|
|
102
76
|
|
|
103
|
-
// Performance
|
|
104
|
-
migrationBatchSize?: number //
|
|
105
|
-
|
|
77
|
+
// Performance
|
|
78
|
+
migrationBatchSize?: number // Items per batch (default: 10)
|
|
79
|
+
migrationConcurrency?: number // Parallel items within a batch (default: 1)
|
|
80
|
+
wpRequestDelay?: number // Delay in ms between WP API requests (default: 0)
|
|
106
81
|
|
|
107
|
-
// Media
|
|
108
|
-
enableMediaDownload?: boolean // Download
|
|
82
|
+
// Media
|
|
83
|
+
enableMediaDownload?: boolean // Download files from WordPress (default: false)
|
|
109
84
|
maxMediaFileSize?: number // Max file size in bytes (default: 10MB)
|
|
85
|
+
mediaUploadPath?: string // Custom upload directory for media files
|
|
110
86
|
allowedMediaTypes?: string[] // Allowed MIME types
|
|
111
87
|
allowSelfSignedCerts?: boolean // Allow self-signed SSL (dev only)
|
|
88
|
+
|
|
89
|
+
// Access Control
|
|
90
|
+
access?: (args: { req: PayloadRequest }) => boolean | Promise<boolean>
|
|
112
91
|
}
|
|
113
92
|
|
|
114
93
|
type WordPressCollectionMapping = {
|
|
115
|
-
wpPostType: string // WordPress content type
|
|
116
|
-
fieldMapping?: Record<string, string> //
|
|
117
|
-
enableBlocks?: boolean // Convert Gutenberg blocks
|
|
94
|
+
wpPostType: string // WordPress content type slug
|
|
95
|
+
fieldMapping?: Record<string, string> // WP field path → Payload field path
|
|
96
|
+
enableBlocks?: boolean // Convert Gutenberg blocks to Lexical
|
|
118
97
|
customFields?: string[] // ACF field names to migrate
|
|
119
|
-
importContentMedia?: boolean // Auto-import content
|
|
98
|
+
importContentMedia?: boolean // Auto-import images from content HTML
|
|
99
|
+
disableHtmlConversion?: boolean // Skip HTML-to-Lexical conversion
|
|
120
100
|
}
|
|
121
101
|
```
|
|
122
102
|
|
|
123
|
-
##
|
|
124
|
-
|
|
125
|
-
The plugin creates the following collections and components in your PayloadCMS instance:
|
|
126
|
-
|
|
127
|
-
### Collections Added
|
|
128
|
-
|
|
129
|
-
1. **`wordpress-migration`**: Core collection for managing migration jobs
|
|
130
|
-
- Job configuration and status tracking
|
|
131
|
-
- Progress monitoring with detailed logs
|
|
132
|
-
- Built-in dashboard interface
|
|
103
|
+
## Plugin Architecture
|
|
133
104
|
|
|
134
|
-
|
|
135
|
-
- `migratedFromWordPress.wpPostId`: Original WordPress post ID
|
|
136
|
-
- `migratedFromWordPress.wpPostType`: WordPress content type
|
|
137
|
-
- `migratedFromWordPress.migrationDate`: Migration timestamp
|
|
105
|
+
### Collections
|
|
138
106
|
|
|
139
|
-
|
|
107
|
+
The plugin creates a `wordpress-migration` collection for job management and adds `migratedFromWordPress` metadata fields to configured target collections:
|
|
140
108
|
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
- **Field Mapping Interface**: Visual field mapping with source/destination field analysis
|
|
145
|
-
- **Job Monitor**: Live progress tracking with success/failure metrics
|
|
109
|
+
- `migratedFromWordPress.wpPostId` — original WordPress post ID
|
|
110
|
+
- `migratedFromWordPress.wpPostType` — WordPress content type
|
|
111
|
+
- `migratedFromWordPress.migrationDate` — migration timestamp
|
|
146
112
|
|
|
147
113
|
### API Endpoints
|
|
148
114
|
|
|
149
|
-
The plugin adds these endpoints to your PayloadCMS API:
|
|
150
|
-
|
|
151
115
|
```
|
|
152
116
|
POST /api/wordpress/test-connection # Test WordPress connectivity
|
|
153
117
|
GET /api/wordpress/migration-summary # Dashboard data with caching
|
|
154
118
|
POST /api/wordpress/discover-content # Content type discovery
|
|
155
|
-
GET /api/wordpress/migration-jobs # Job status
|
|
156
|
-
POST /api/wordpress/migration-jobs # Start
|
|
119
|
+
GET /api/wordpress/migration-jobs # Job status
|
|
120
|
+
POST /api/wordpress/migration-jobs # Start/retry/resume/rollback jobs
|
|
157
121
|
PUT /api/wordpress/migration-jobs # Pause/resume jobs
|
|
158
122
|
DELETE /api/wordpress/migration-jobs # Delete jobs
|
|
159
123
|
POST /api/wordpress/content-fields # Analyze WordPress fields
|
|
160
124
|
GET /api/collections/:slug/fields # Analyze PayloadCMS fields
|
|
161
125
|
```
|
|
162
126
|
|
|
163
|
-
##
|
|
164
|
-
|
|
165
|
-
### Supported Content Types
|
|
166
|
-
|
|
167
|
-
| Content Type | Features | Notes |
|
|
168
|
-
| --------------------- | ------------------------------------------------------- | --------------------------------- |
|
|
169
|
-
| **Posts** | ✅ Content, metadata, categories, tags, featured images | Full Gutenberg block conversion |
|
|
170
|
-
| **Pages** | ✅ Content, metadata, featured images, custom fields | Hierarchical structure support |
|
|
171
|
-
| **Media** | ✅ File downloads, metadata, alt text, captions | MIME type filtering & size limits |
|
|
172
|
-
| **Categories** | ✅ Names, descriptions, hierarchy, counts | Taxonomy relationships |
|
|
173
|
-
| **Tags** | ✅ Names, descriptions, post associations | Tag cloud support |
|
|
174
|
-
| **Users** | ✅ User data, roles, capabilities, avatars | Permission mapping |
|
|
175
|
-
| **Custom Post Types** | ✅ Auto-discovery, custom fields, metadata | ACF integration |
|
|
176
|
-
|
|
177
|
-
### Advanced Content Processing
|
|
178
|
-
|
|
179
|
-
- **HTML to Lexical Conversion**: Sophisticated converter handles complex HTML structures
|
|
180
|
-
- **Gutenberg Block Processing**: Converts blocks to PayloadCMS block format
|
|
181
|
-
- **ACF Field Migration**: Automatic Advanced Custom Fields detection and migration
|
|
182
|
-
- **Media Auto-Import**: Scans content for WordPress media URLs and imports automatically
|
|
183
|
-
- **Relationship Preservation**: Maintains post-category, post-tag, and other relationships
|
|
184
|
-
|
|
185
|
-
## 🖼️ Media Migration
|
|
127
|
+
## Supported Content Types
|
|
186
128
|
|
|
187
|
-
|
|
129
|
+
| Content Type | Features | Notes |
|
|
130
|
+
| --------------------- | ---------------------------------------------------- | ----------------------------------- |
|
|
131
|
+
| **Posts** | Content, metadata, categories, tags, featured images | Full Gutenberg block conversion |
|
|
132
|
+
| **Pages** | Content, metadata, featured images, custom fields | Hierarchical structure support |
|
|
133
|
+
| **Media** | File downloads, metadata, alt text, captions | MIME type filtering and size limits |
|
|
134
|
+
| **Categories** | Names, descriptions, hierarchy, counts | Taxonomy relationships |
|
|
135
|
+
| **Tags** | Names, descriptions, post associations | — |
|
|
136
|
+
| **Users** | User data, roles, capabilities, avatars | Permission mapping |
|
|
137
|
+
| **Custom Post Types** | Auto-discovery, custom fields, metadata | ACF integration |
|
|
188
138
|
|
|
189
|
-
|
|
139
|
+
## Media Migration
|
|
190
140
|
|
|
191
|
-
|
|
192
|
-
2. **Full File Migration**: Downloads files from WordPress and uploads them to PayloadCMS
|
|
141
|
+
Two modes:
|
|
193
142
|
|
|
194
|
-
|
|
143
|
+
1. **Metadata Only** (default) — migrates titles, descriptions, alt text, and URLs
|
|
144
|
+
2. **Full File Migration** — downloads files from WordPress and uploads to PayloadCMS
|
|
195
145
|
|
|
196
146
|
```typescript
|
|
197
147
|
payloadWordPressMigrator({
|
|
198
|
-
enableMediaDownload: true,
|
|
199
|
-
maxMediaFileSize: 50 * 1024 * 1024, // 50MB
|
|
148
|
+
enableMediaDownload: true,
|
|
149
|
+
maxMediaFileSize: 50 * 1024 * 1024, // 50MB
|
|
200
150
|
allowedMediaTypes: [
|
|
201
151
|
'image/jpeg',
|
|
202
152
|
'image/png',
|
|
@@ -205,184 +155,75 @@ payloadWordPressMigrator({
|
|
|
205
155
|
'application/pdf',
|
|
206
156
|
'video/mp4',
|
|
207
157
|
],
|
|
208
|
-
allowSelfSignedCerts: true, // For development only
|
|
209
158
|
})
|
|
210
159
|
```
|
|
211
160
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
#### Featured Image Auto-Import
|
|
215
|
-
|
|
216
|
-
- Automatically detects and imports featured images using WordPress `_embed` data
|
|
217
|
-
- Fallback support when `_embed` data is unavailable
|
|
218
|
-
- Creates PayloadCMS media records with actual file downloads
|
|
219
|
-
- Links imported media to posts/pages via `featuredImage` field
|
|
220
|
-
|
|
221
|
-
#### Content Media Auto-Import
|
|
222
|
-
|
|
223
|
-
- Scans HTML content for WordPress media URLs (`wp-content/uploads`)
|
|
224
|
-
- Downloads and imports images referenced in post/page content
|
|
225
|
-
- Preserves alt text and title attributes
|
|
226
|
-
- Smart duplicate detection to avoid re-importing existing files
|
|
227
|
-
|
|
228
|
-
#### MediaBlock Conversion
|
|
229
|
-
|
|
230
|
-
When migrating content with `enableMediaDownload: true`, the plugin now converts HTML `<img>` tags to proper PayloadCMS MediaBlocks:
|
|
231
|
-
|
|
232
|
-
- **HTML Images → MediaBlocks**: Converts inline images to structured MediaBlock components
|
|
233
|
-
- **Media Import Integration**: Automatically downloads and links media files to MediaBlocks
|
|
234
|
-
- **Rich Editor Support**: MediaBlocks display properly in PayloadCMS Lexical editor
|
|
235
|
-
- **Frontend Rendering**: Works seamlessly with PayloadCMS RichText component
|
|
236
|
-
- **Metadata Preservation**: Maintains alt text, titles, and dimensions for accessibility
|
|
237
|
-
|
|
238
|
-
#### Configuration Example
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
collections: {
|
|
242
|
-
posts: {
|
|
243
|
-
wpPostType: 'post',
|
|
244
|
-
importContentMedia: true, // Enable content media auto-import
|
|
245
|
-
},
|
|
246
|
-
media: {
|
|
247
|
-
wpPostType: 'media' // Required for media storage
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
enableMediaDownload: true // Required for auto-import
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Migration Workflow Options
|
|
254
|
-
|
|
255
|
-
1. **Recommended**: Migrate posts/pages only - media will be auto-imported
|
|
256
|
-
2. **Alternative**: Migrate media first, then posts/pages (avoids duplicates)
|
|
161
|
+
Auto-import features:
|
|
257
162
|
|
|
258
|
-
|
|
163
|
+
- **Featured images** — detected via WordPress `_embed` data, downloaded and linked
|
|
164
|
+
- **Content media** — scans HTML for `wp-content/uploads` URLs, imports automatically
|
|
165
|
+
- **MediaBlock conversion** — HTML `<img>` tags converted to PayloadCMS MediaBlocks
|
|
259
166
|
|
|
260
|
-
|
|
261
|
-
- Large files streamed to minimize memory usage
|
|
262
|
-
- Failed downloads don't stop the entire migration process
|
|
263
|
-
- Media auto-import runs in parallel for optimal performance
|
|
264
|
-
- Smart duplicate detection prevents re-importing existing media
|
|
167
|
+
**Recommended workflow:** Migrate posts/pages only — media referenced in content will be auto-imported.
|
|
265
168
|
|
|
266
|
-
##
|
|
169
|
+
## Advanced Configuration
|
|
267
170
|
|
|
268
|
-
### Complete
|
|
171
|
+
### Complete Example
|
|
269
172
|
|
|
270
173
|
```typescript
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
enableBlocks: true,
|
|
287
|
-
importContentMedia: true,
|
|
288
|
-
customFields: ['_yoast_wpseo_title', '_yoast_wpseo_metadesc'],
|
|
289
|
-
fieldMapping: {
|
|
290
|
-
'title.rendered': 'title',
|
|
291
|
-
'content.rendered': 'content',
|
|
292
|
-
'excerpt.rendered': 'excerpt',
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
pages: {
|
|
296
|
-
wpPostType: 'page',
|
|
297
|
-
enableBlocks: true,
|
|
298
|
-
importContentMedia: true,
|
|
299
|
-
disableHtmlConversion: false, // Enable HTML to Lexical conversion
|
|
300
|
-
},
|
|
301
|
-
media: {
|
|
302
|
-
wpPostType: 'media',
|
|
303
|
-
},
|
|
304
|
-
categories: {
|
|
305
|
-
wpPostType: 'category',
|
|
306
|
-
},
|
|
307
|
-
products: {
|
|
308
|
-
// Custom post type example
|
|
309
|
-
wpPostType: 'product',
|
|
310
|
-
enableBlocks: false,
|
|
311
|
-
customFields: ['_price', '_stock_status', '_featured'],
|
|
312
|
-
},
|
|
174
|
+
payloadWordPressMigrator({
|
|
175
|
+
wpSiteUrl: process.env.WORDPRESS_API_URL,
|
|
176
|
+
wpUsername: process.env.WORDPRESS_USERNAME,
|
|
177
|
+
wpPassword: process.env.WORDPRESS_APP_PASSWORD,
|
|
178
|
+
|
|
179
|
+
collections: {
|
|
180
|
+
posts: {
|
|
181
|
+
wpPostType: 'post',
|
|
182
|
+
enableBlocks: true,
|
|
183
|
+
importContentMedia: true,
|
|
184
|
+
customFields: ['_yoast_wpseo_title', '_yoast_wpseo_metadesc'],
|
|
185
|
+
fieldMapping: {
|
|
186
|
+
'title.rendered': 'title',
|
|
187
|
+
'content.rendered': 'content',
|
|
188
|
+
'excerpt.rendered': 'excerpt',
|
|
313
189
|
},
|
|
190
|
+
},
|
|
191
|
+
pages: { wpPostType: 'page', enableBlocks: true, importContentMedia: true },
|
|
192
|
+
media: { wpPostType: 'media' },
|
|
193
|
+
categories: { wpPostType: 'category' },
|
|
194
|
+
products: {
|
|
195
|
+
wpPostType: 'product',
|
|
196
|
+
customFields: ['_price', '_stock_status', '_featured'],
|
|
197
|
+
},
|
|
198
|
+
},
|
|
314
199
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
200
|
+
migrationBatchSize: 25,
|
|
201
|
+
migrationConcurrency: 3,
|
|
202
|
+
enableMediaDownload: true,
|
|
203
|
+
maxMediaFileSize: 50 * 1024 * 1024,
|
|
204
|
+
allowSelfSignedCerts: process.env.NODE_ENV === 'development',
|
|
318
205
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
maxMediaFileSize: 50 * 1024 * 1024, // 50MB
|
|
322
|
-
allowedMediaTypes: [
|
|
323
|
-
'image/jpeg',
|
|
324
|
-
'image/png',
|
|
325
|
-
'image/gif',
|
|
326
|
-
'image/webp',
|
|
327
|
-
'image/svg+xml',
|
|
328
|
-
'application/pdf',
|
|
329
|
-
'video/mp4',
|
|
330
|
-
'video/webm',
|
|
331
|
-
'audio/mpeg',
|
|
332
|
-
],
|
|
333
|
-
|
|
334
|
-
// Development Settings
|
|
335
|
-
allowSelfSignedCerts: process.env.NODE_ENV === 'development',
|
|
336
|
-
|
|
337
|
-
// Plugin Control
|
|
338
|
-
disabled: false,
|
|
339
|
-
disableDashboard: false,
|
|
340
|
-
}),
|
|
341
|
-
],
|
|
206
|
+
// Restrict to admin users only
|
|
207
|
+
access: ({ req }) => req.user?.role === 'admin',
|
|
342
208
|
})
|
|
343
209
|
```
|
|
344
210
|
|
|
345
|
-
### Field Mapping
|
|
211
|
+
### Field Mapping
|
|
346
212
|
|
|
347
|
-
|
|
213
|
+
Dot-notation paths are supported:
|
|
348
214
|
|
|
349
215
|
```typescript
|
|
350
216
|
fieldMapping: {
|
|
351
|
-
// WordPress field path → PayloadCMS field path
|
|
352
217
|
'title.rendered': 'title',
|
|
353
218
|
'content.rendered': 'content',
|
|
354
219
|
'meta._yoast_wpseo_title': 'seo.title',
|
|
355
220
|
'acf.hero_image': 'hero.image',
|
|
356
|
-
'custom_field_name': 'mappedField'
|
|
357
221
|
}
|
|
358
222
|
```
|
|
359
223
|
|
|
360
|
-
##
|
|
361
|
-
|
|
362
|
-
The plugin provides a comprehensive React-based dashboard accessible at `/admin/collections/wordpress-migration`:
|
|
363
|
-
|
|
364
|
-
### Dashboard Features
|
|
365
|
-
|
|
366
|
-
- **Site Configuration**: Secure WordPress credentials management
|
|
367
|
-
- **Content Discovery**: Automatic scan and analysis of available content
|
|
368
|
-
- **Job Creation**: Visual job setup with field mapping interface
|
|
369
|
-
- **Real-time Monitoring**: Live progress updates with success/failure metrics
|
|
370
|
-
- **Job Controls**: Start, pause, resume, retry operations
|
|
371
|
-
- **Error Reporting**: Detailed logs and error analysis
|
|
372
|
-
|
|
373
|
-
### Dashboard Screenshots
|
|
224
|
+
## Programmatic API
|
|
374
225
|
|
|
375
|
-
The
|
|
376
|
-
|
|
377
|
-
1. **Configuration Panel**: WordPress site setup and testing
|
|
378
|
-
2. **Content Overview**: Discovered content types with item counts
|
|
379
|
-
3. **Job Management**: Active and completed migration jobs
|
|
380
|
-
4. **Progress Tracking**: Visual progress bars with detailed statistics
|
|
381
|
-
5. **Log Viewer**: Real-time migration logs and error reporting
|
|
382
|
-
|
|
383
|
-
## 🔌 Programmatic API
|
|
384
|
-
|
|
385
|
-
The plugin exports utilities that can be used outside the dashboard for scripted or custom migrations.
|
|
226
|
+
The plugin exports utilities for scripted migrations outside the dashboard.
|
|
386
227
|
|
|
387
228
|
### WordPress Client
|
|
388
229
|
|
|
@@ -395,192 +236,80 @@ const client = new WordPressClient({
|
|
|
395
236
|
wpPassword: 'xxxx xxxx xxxx xxxx',
|
|
396
237
|
})
|
|
397
238
|
|
|
398
|
-
// Discover available content types
|
|
399
239
|
const contentTypes = await client.discoverContent()
|
|
400
|
-
|
|
401
|
-
// Fetch fields for a specific content type
|
|
402
240
|
const fields = await client.fetchContentFields('post')
|
|
403
241
|
```
|
|
404
242
|
|
|
405
|
-
###
|
|
406
|
-
|
|
407
|
-
```typescript
|
|
408
|
-
import { transformWordPressContent } from 'payload-wordpress-migrator/dist/utils/content/index.js'
|
|
409
|
-
|
|
410
|
-
const payloadData = await transformWordPressContent(
|
|
411
|
-
wpItem, // WordPress REST API item
|
|
412
|
-
'post', // Content type
|
|
413
|
-
jobConfig, // Job configuration (batchSize, enableBlocks, fieldMapping)
|
|
414
|
-
payload, // Payload instance
|
|
415
|
-
pluginOptions // Plugin config
|
|
416
|
-
)
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### HTML to Lexical Conversion
|
|
243
|
+
### HTML to Lexical
|
|
420
244
|
|
|
421
245
|
```typescript
|
|
422
246
|
import { convertHtmlToLexical } from 'payload-wordpress-migrator/dist/utils/lexical/index.js'
|
|
423
247
|
|
|
424
248
|
const lexicalContent = convertHtmlToLexical('<p>Hello <strong>world</strong></p>')
|
|
425
|
-
// Returns a Lexical root node ready for PayloadCMS rich text fields
|
|
426
249
|
```
|
|
427
250
|
|
|
428
|
-
###
|
|
251
|
+
### Content Transformation
|
|
429
252
|
|
|
430
253
|
```typescript
|
|
431
|
-
import {
|
|
254
|
+
import { transformWordPressContent } from 'payload-wordpress-migrator/dist/utils/content/index.js'
|
|
432
255
|
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
payload
|
|
256
|
+
const payloadData = await transformWordPressContent(
|
|
257
|
+
wpItem,
|
|
258
|
+
'post',
|
|
259
|
+
jobConfig,
|
|
260
|
+
payload,
|
|
261
|
+
pluginOptions,
|
|
438
262
|
)
|
|
439
263
|
```
|
|
440
264
|
|
|
441
|
-
> **Note:** These
|
|
442
|
-
|
|
443
|
-
## 🛠️ Development & Extension
|
|
444
|
-
|
|
445
|
-
### Plugin Structure
|
|
446
|
-
|
|
447
|
-
```
|
|
448
|
-
src/
|
|
449
|
-
├── components/ # React UI components
|
|
450
|
-
│ ├── dashboard/ # Dashboard sub-components
|
|
451
|
-
│ │ ├── SiteConfigPanel.tsx # WordPress connection form
|
|
452
|
-
│ │ ├── StatsOverview.tsx # Summary stat cards
|
|
453
|
-
│ │ ├── JobsTable.tsx # Migration jobs table
|
|
454
|
-
│ │ ├── JobActionButtons.tsx # Per-job action buttons
|
|
455
|
-
│ │ ├── LogViewer.tsx # Combined log display
|
|
456
|
-
│ │ ├── useMigrationDashboard.ts # State, effects, and handlers
|
|
457
|
-
│ │ └── types.ts # Dashboard-specific types
|
|
458
|
-
│ ├── MigrationDashboardClient.tsx # Dashboard composition shell
|
|
459
|
-
│ ├── ContentTypeSelect.tsx # Content type picker
|
|
460
|
-
│ ├── FieldMappingConfiguration.tsx # Field mapper
|
|
461
|
-
│ └── SimpleFieldMapping.tsx # Simple mapping UI
|
|
462
|
-
├── utils/
|
|
463
|
-
│ ├── wordpress/client.ts # WordPress REST API client
|
|
464
|
-
│ ├── migration/orchestrator.ts # Job execution engine
|
|
465
|
-
│ ├── content/transformer.ts # WP → Payload content transform
|
|
466
|
-
│ ├── lexical/htmlToLexicalConverter.ts # HTML → Lexical conversion
|
|
467
|
-
│ └── ... # Media, fields, helpers, endpoints
|
|
468
|
-
└── index.ts # Plugin entry point
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
### Error Handling
|
|
472
|
-
|
|
473
|
-
The plugin provides comprehensive error handling:
|
|
474
|
-
|
|
475
|
-
- **Connection Errors**: WordPress API connectivity issues
|
|
476
|
-
- **Authentication Errors**: Invalid credentials or permissions
|
|
477
|
-
- **Content Errors**: Malformed content or missing fields
|
|
478
|
-
- **Media Errors**: Download failures or file size limits
|
|
479
|
-
- **Database Errors**: PayloadCMS creation failures
|
|
480
|
-
|
|
481
|
-
## 📊 Migration Best Practices
|
|
482
|
-
|
|
483
|
-
### Pre-Migration Checklist
|
|
265
|
+
> **Note:** These are internal paths (`dist/utils/...`). The public package export exposes only the plugin function and config types. Internal APIs may change between minor versions.
|
|
484
266
|
|
|
485
|
-
|
|
486
|
-
- Generate application password
|
|
487
|
-
- Verify REST API access
|
|
488
|
-
- Check user permissions
|
|
489
|
-
- Test SSL certificate
|
|
267
|
+
## Migration Best Practices
|
|
490
268
|
|
|
491
|
-
|
|
492
|
-
- Configure target collections
|
|
493
|
-
- Set up field mappings
|
|
494
|
-
- Test media collection setup
|
|
495
|
-
- Verify storage configuration
|
|
269
|
+
**Recommended migration order:**
|
|
496
270
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
271
|
+
1. Categories and Tags (establishes taxonomy)
|
|
272
|
+
2. Media (creates media library)
|
|
273
|
+
3. Pages (static content)
|
|
274
|
+
4. Posts (blog content with relationships)
|
|
275
|
+
5. Users (author information)
|
|
276
|
+
6. Custom Post Types
|
|
502
277
|
|
|
503
|
-
|
|
278
|
+
**Performance tips:**
|
|
504
279
|
|
|
505
|
-
|
|
280
|
+
- Start with `migrationBatchSize: 10` for testing, increase for production runs
|
|
281
|
+
- Use `migrationConcurrency: 3-5` for faster processing
|
|
282
|
+
- Use dry run mode to preview before committing
|
|
283
|
+
- Use resume for interrupted migrations
|
|
506
284
|
|
|
507
|
-
|
|
508
|
-
2. **Media Files** (creates media library)
|
|
509
|
-
3. **Pages** (static content first)
|
|
510
|
-
4. **Posts** (blog content with relationships)
|
|
511
|
-
5. **Users** (author information)
|
|
512
|
-
6. **Custom Post Types** (specialized content)
|
|
285
|
+
## Troubleshooting
|
|
513
286
|
|
|
514
|
-
|
|
287
|
+
| Problem | Cause | Solution |
|
|
288
|
+
| ------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
289
|
+
| **"Authentication failed"** | Wrong credentials, or REST API disabled | Verify you're using an **Application Password** (not your login password). Confirm the REST API is accessible at `https://your-site.com/wp-json/` |
|
|
290
|
+
| **Content types not discovered** | WordPress permalinks set to "Plain" | In WordPress Admin > Settings > Permalinks, switch to any structure other than "Plain" |
|
|
291
|
+
| **Custom post types not found** | CPT not exposed to REST API | Add `'show_in_rest' => true` to your `register_post_type()` call |
|
|
292
|
+
| **SSL certificate errors** | Self-signed or expired certificate | Set `allowSelfSignedCerts: true` for development. In production, use a valid certificate |
|
|
293
|
+
| **Media download fails** | WordPress behind CDN or firewall | Ensure media file URLs (`wp-content/uploads/...`) are accessible from the server running Payload |
|
|
294
|
+
| **`"The following path cannot be queried: migratedFromWordPress"`** | Target collection not in plugin config | Add the collection to the `collections` option so the metadata fields get injected |
|
|
295
|
+
| **Large migration runs out of memory** | Batch size too high for available RAM | Reduce `migrationBatchSize` (try 5) and `migrationConcurrency` (set to 1) |
|
|
296
|
+
| **Lexical content looks wrong** | HTML conversion edge case | Set `disableHtmlConversion: true` on the collection mapping as a workaround, and report the specific HTML that fails |
|
|
297
|
+
| **Duplicate items after resume** | `migratedFromWordPress.wpPostId` field missing | Ensure the collection is listed in the plugin `collections` config — the field is auto-added |
|
|
298
|
+
| **ACF fields not migrated** | Field mapping not configured | Add ACF field names to `customFields` in the collection mapping, or configure explicit `fieldMapping` in the job |
|
|
299
|
+
| **`"MIME type not allowed"` or `"File too large"`** | Media file exceeds limits | Expand `allowedMediaTypes` and increase `maxMediaFileSize` in plugin config |
|
|
515
300
|
|
|
516
|
-
|
|
517
|
-
- Increase batch size (50-100) for production migrations
|
|
518
|
-
- Monitor memory usage during large media migrations
|
|
519
|
-
- Use resume functionality for interrupted migrations
|
|
301
|
+
## Requirements
|
|
520
302
|
|
|
521
|
-
|
|
303
|
+
- Node.js ^18.20.2 || >=20.9.0
|
|
304
|
+
- PayloadCMS ^3.29.0
|
|
305
|
+
- WordPress 5.6+ with REST API enabled
|
|
522
306
|
|
|
523
|
-
|
|
524
|
-
|---------|-------|----------|
|
|
525
|
-
| **"Authentication failed"** | Wrong credentials, or REST API disabled | Verify you're using an **Application Password** (not your login password). Confirm the REST API is accessible at `https://your-site.com/wp-json/` |
|
|
526
|
-
| **Content types not discovered** | WordPress permalinks set to "Plain" | In WordPress Admin > Settings > Permalinks, switch to any structure other than "Plain" |
|
|
527
|
-
| **Custom post types not found** | CPT not exposed to REST API | Add `'show_in_rest' => true` to your `register_post_type()` call |
|
|
528
|
-
| **SSL certificate errors** | Self-signed or expired certificate | Set `allowSelfSignedCerts: true` for development. In production, use a valid certificate |
|
|
529
|
-
| **Media download fails** | WordPress behind CDN or firewall | Ensure media file URLs (`wp-content/uploads/...`) are accessible from the server running Payload |
|
|
530
|
-
| **`"The following path cannot be queried: migratedFromWordPress"`** | Target collection not in plugin config | Add the collection to the `collections` option so the metadata fields get injected |
|
|
531
|
-
| **Large migration runs out of memory** | Batch size too high for available RAM | Reduce `migrationBatchSize` (try 5) and `migrationConcurrency` (set to 1) |
|
|
532
|
-
| **Lexical content looks wrong** | HTML conversion edge case | Set `disableHtmlConversion: true` on the collection mapping as a workaround, and report the specific HTML that fails |
|
|
533
|
-
| **Duplicate items after resume** | `migratedFromWordPress.wpPostId` field missing | Ensure the collection is listed in the plugin `collections` config — the field is auto-added |
|
|
534
|
-
| **ACF fields not migrated** | Field mapping not configured | Add ACF field names to `customFields` in the collection mapping, or configure explicit `fieldMapping` in the job |
|
|
535
|
-
| **`"MIME type not allowed"` or `"File too large"`** | Media file exceeds limits | Expand `allowedMediaTypes` and increase `maxMediaFileSize` in plugin config |
|
|
307
|
+
## License
|
|
536
308
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
- **Node.js**: ^18.20.2 || >=20.9.0
|
|
540
|
-
- **PayloadCMS**: ^3.29.0
|
|
541
|
-
- **Package Manager**: pnpm ^9 || ^10
|
|
542
|
-
- **WordPress**: 5.6+ with REST API enabled
|
|
543
|
-
- **Memory**: 512MB+ recommended for media migrations
|
|
544
|
-
- **Storage**: Adequate space for media file imports
|
|
545
|
-
|
|
546
|
-
## 📈 Performance Considerations
|
|
547
|
-
|
|
548
|
-
- **Batch Processing**: Configurable batch sizes prevent memory overflow
|
|
549
|
-
- **Background Jobs**: Non-blocking migration execution
|
|
550
|
-
- **Progress Persistence**: Resume interrupted migrations
|
|
551
|
-
- **Memory Management**: Efficient file streaming for large media
|
|
552
|
-
- **Cache Management**: Intelligent caching with invalidation
|
|
553
|
-
- **Parallel Processing**: Concurrent media imports for optimal speed
|
|
554
|
-
|
|
555
|
-
## 🤝 Contributing
|
|
556
|
-
|
|
557
|
-
We welcome contributions! Areas for enhancement:
|
|
558
|
-
|
|
559
|
-
- Additional content type support
|
|
560
|
-
- Enhanced field mapping UI
|
|
561
|
-
- Performance optimizations
|
|
562
|
-
- Advanced content transformations
|
|
563
|
-
- Integration tests
|
|
564
|
-
- Documentation improvements
|
|
565
|
-
|
|
566
|
-
## 📝 License
|
|
567
|
-
|
|
568
|
-
MIT License - see [LICENSE](LICENSE) file for details.
|
|
569
|
-
|
|
570
|
-
## 🎯 Roadmap
|
|
571
|
-
|
|
572
|
-
- [ ] WordPress multisite support
|
|
573
|
-
- [ ] Advanced Custom Fields Pro support
|
|
574
|
-
- [ ] WooCommerce product migration
|
|
575
|
-
- [ ] Automated testing suite
|
|
576
|
-
- [ ] Docker development environment
|
|
577
|
-
- [ ] Migration templates and presets
|
|
578
|
-
- [ ] Webhook integration for real-time sync
|
|
309
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
579
310
|
|
|
580
311
|
---
|
|
581
312
|
|
|
582
|
-
**Author
|
|
583
|
-
|
|
584
|
-
**Repository**: [GitHub](https://github.com/Brightscout/payload-wordpress-migrator)
|
|
313
|
+
**Author:** [Igor Abdulovic](mailto:igor.abdulovic@brightscout.com) at [Brightscout](https://brightscout.com)
|
|
585
314
|
|
|
586
|
-
**
|
|
315
|
+
**Repository:** [GitHub](https://github.com/Brightscout/payload-wordpress-migrator)
|