WP Manifestindependent plugin directory
manifest / updates / data-migrator-plugin

Data Migrator

Securely migrate status-preserving WordPress posts and lightweight page structures, terms, metadata, and media between sites through authenticated REST endpoints and a resumable background queue.

by Mubeen Hassan · github.com/mubeenhassan-dev/data-migrator-plugin

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/mubeenhassan-dev/data-migrator-plugin/archive/refs/heads/main.zip

Readme

Data Migrator

Data Migrator is a custom WordPress plugin for migrating data directly from one WordPress website to another through authenticated REST API communication.

The plugin is designed around a Source / Destination architecture: the old website exposes protected read-only migration endpoints, while the new website creates resumable migration jobs, imports data in batches, tracks mappings, and provides live progress and migration history.

Current version: 0.8.3
Requires WordPress: 6.0+
Requires PHP: 7.4+
License: GPL-2.0-or-later

Current migration support

Users

Data Migrator can migrate WordPress user accounts while preserving the user's existing login password.

The Users migration includes:

  • Username and email address
  • Display name and nicename
  • Website URL and registration date
  • User status
  • Current-site roles and capabilities
  • User level
  • Non-authentication profile/user metadata
  • The existing WordPress user_pass hash
  • Source-to-destination user ID mappings

The password is never requested, exposed, or transferred in plaintext. The destination stores the source WordPress password hash without hashing it again, allowing migrated users to continue signing in with the same password.

For security, the following authentication state is intentionally not migrated:

  • Active WordPress sessions
  • session_tokens
  • WordPress Application Passwords
  • Password reset/activation keys
  • Network super-admin grants
  • Data Migrator's own internal metadata

When Users and Posts are migrated together, Users run first so imported posts can map back to their original migrated authors. A configurable destination-author fallback remains available when an author cannot be mapped.

WooCommerce Products

WooCommerce Products are a first-class migration type. WooCommerce must be active on both the source and destination websites.

The administrator can choose between two product-data modes:

  • Products & variations only — recommended: recreates the standard WooCommerce catalog without copying arbitrary plugin/custom metadata. It includes product type, name/description, SKU, prices and sale dates, inventory/stock settings, tax/shipping fields, dimensions, purchase note, catalog visibility, categories, tags, product brands when registered, shipping class, global/custom attributes, default attributes, featured/gallery images, downloadable files, upsells, cross-sells, grouped-product relationships, and variable-product variations.
  • Full Product Data: includes everything above plus non-core product and variation metadata/custom fields, term metadata, and registered custom product taxonomies. Custom meta keys are preserved exactly. Plugin-specific data is most useful when the same extension/custom code exists on the destination.

Simple products are imported directly. Variable products use a separate paginated Variations stage so large catalogs do not embed every variation in a parent-product response. When the selected source products have no variations, the Variations stage is omitted.

Product images, gallery images, product-category thumbnails, and local downloadable files reuse the shared Media queue. After media has finished, Product setup connects migrated attachments, downloads, upsells/cross-sells, grouped children, category thumbnails, and variable-product synchronization.

Source-to-destination mappings and SKU matching make repeat migrations duplicate-safe. Existing products can be updated or skipped through the shared duplicate strategy.

Product reviews/orders/customers are not part of the Products migration in this release. Extension-specific product types can be recreated only when the extension providing that type is available on the destination; Full Product Data preserves their non-core metadata but cannot reproduce behavior for a missing extension.

Posts

Posts can preserve:

  • Title
  • Content
  • Excerpt
  • Slug
  • Original WordPress status
  • Publish and modified dates
  • Categories and tags
  • Author mapping
  • Featured images
  • Embedded media and galleries
  • Attachments
  • Public custom fields
  • Common Yoast SEO, Rank Math, and AIOSEO metadata

Supported post statuses include Published, Draft, Pending Review, Private, and Scheduled.

Pages

Pages intentionally use a lightweight structural migration because the destination website may use a different theme, builder, or page design.

The page importer migrates:

  • Title
  • Slug
  • Original date
  • Original status
  • Parent/child relationships

It does not replace destination page content, Gutenberg blocks, Elementor/design data, templates, SEO metadata, or custom fields. When a previously imported page is updated, existing destination page content remains intact.

Terms and media

Post migrations include the supporting taxonomy stages for categories and tags, including category parents.

Media options include:

  • Media used by selected posts — recommended
  • Featured images only
  • Entire source Media Library
  • Skip media

Media processing uses batching, duplicate detection, mappings, progress tracking, and background workers.

Migration scope and stages

The worker builds the stage sequence from the import types actually selected by the administrator. Unselected migration types are not processed or displayed as fake stages.

Examples:

Selected import Stages
Users Users
Pages Pages
Products (simple only) Products → Media → Product setup
Products (with variations) Products → Variations → Media → Product setup
Users + Pages Users → Pages
Posts, media skipped Terms → Posts → Finalize → Verify
Posts with media Terms → Posts → Media → Finalize → Verify
Users + Products + Posts + Pages Users → Products → Variations* → Terms → Posts → Pages → Media → Product setup → Finalize → Verify

* The Variations stage is omitted when no selected source products have variations.

Source and destination modes

The plugin can run in:

  • Source mode — exposes authenticated migration endpoints
  • Destination mode — connects to a source and imports data
  • Both mode — enables both responsibilities on the same installation

The responsibilities remain separated internally even when Both mode is selected.

Connection flow

The destination uses a single first-time Save & Connect action.

  1. Enter the source URL, WordPress username, and Application Password.
  2. Click Save & Connect.
  3. Data Migrator performs a lightweight authenticated /status API health check only.
  4. Credentials are encrypted and stored only if that check succeeds.
  5. After a connection is saved, the fields are locked and Test Connection becomes available.

Connection testing does not fetch products, posts, pages, users, media, or migration totals. Product/WooCommerce capability and counts are checked only when Products is selected while creating a migration job.

Forget connection uses a custom confirmation modal and removes the saved username and encrypted Application Password. The source URL remains available for convenience.

Users endpoint security

User migration uses dedicated source endpoints:

/wp-json/data-migrator/v1/users/status
/wp-json/data-migrator/v1/users

The Users endpoints:

  • Require an authenticated administrator with manage_options
  • Use the dedicated status endpoint for permission/count preflight
  • Return user data in batches
  • Mark responses as non-cacheable
  • Never put password hashes into migration activity logs
  • Never persist password hashes in migration queue payloads

HTTPS and local development

Public source websites must use HTTPS for Users export.

Supported examples:

https://oldsite.com  →  https://newsite.com
https://oldsite.com  →  http://newsite.local
http://oldsite.local →  http://newsite.local

HTTP user export is allowed only for recognized local-development sources. WordPress Application Password authentication must also be available on that local source; for normal WordPress local development this commonly means setting WP_ENVIRONMENT_TYPE to local or using local HTTPS.

Do not enable relaxed local/private URL or SSL-verification settings on production destinations.

Background processing

Data Migrator uses:

  1. Action Scheduler when its API is available
  2. WordPress Cron as a fallback
  3. Live-page worker requests to improve throughput while the migration dashboard is open

Migration state is stored in the database, so refreshing or reopening the admin page does not lose the job.

The migration system is designed to remain:

  • Resumable
  • Batch-based
  • Duplicate-safe
  • Mapping-aware
  • Memory-conscious
  • Traceable through activity logs

Live migration dashboard

While a migration is active, the dashboard shows:

  • Overall progress
  • Live elapsed time
  • Current stage
  • Current item/operation
  • Imported count
  • Updated count
  • Skipped count
  • Failed count
  • Recent activity
  • Pause / Resume / Cancel controls when appropriate

The elapsed timer runs client-side every second and is synchronized against the server's elapsed duration. It no longer waits for a worker/status request before visually updating.

When a migration becomes Completed, Failed, or Cancelled, live polling and activity DOM updates stop.

Migration History

Migration History is intentionally separate from the live processing dashboard.

The history table displays completed and previous migration records without starting the live poller. Each row provides View logs, which opens a custom log browser modal.

The logs modal includes:

  • Scope-aware title such as Log #27 - Users + Posts Import
  • Total log count
  • Matching-result count
  • Search
  • Level filter
  • Log type filter
  • 25 / 50 / 100 per-page selection
  • AJAX pagination with First / Previous / numbered pages / Next / Last
  • Browser-local timestamps
  • One controlled modal-body scroll region

Logs are loaded on demand only when the modal is opened.

History cleanup and safe rollback

Data Migrator treats history deletion and imported-content rollback as two different operations.

  • Delete history removes one terminal migration record together with its logs, queue records, and rollback audit data. Destination content is not deleted.
  • Clear history performs the same history-only cleanup for all completed, failed, and cancelled migrations while active migrations remain untouched.
  • Rollback content selectively removes destination objects that the selected migration actually created. Rollback runs through a background queue (Action Scheduler when available, WordPress Cron fallback) while AJAX only monitors deleted, protected/shared, failed, and remaining counts.

Starting with v0.8.0, every imported object receives a migration ownership audit record. Objects that already existed and were only updated or skipped are recorded as protected rather than owned. If an object created by one migration is later reused by another migration, rollback treats it as shared and leaves it in place.

Rollback is dependency-aware: product variations are removed before products, posts/pages before media and taxonomies, and users last. Taxonomy terms are deleted only when they are no longer assigned, and user accounts are protected when deleting them would be unsafe. The feature is deliberately a safe delete of migration-created objects, not a snapshot restore of pre-existing objects.

Starting with v0.8.2, rollback execution is independent of the Migration History page. Starting a rollback queues a dedicated background worker. If Action Scheduler is available it is used automatically; otherwise Data Migrator schedules WordPress Cron events. The modal polls read-only rollback status through AJAX, so it can be closed and reopened without stopping the rollback. The worker processes one dependency-aware batch at a time, uses a migration-specific lock to avoid concurrent deletion workers, and retries unexpected worker failures with a bounded retry count.

Migrations created before v0.8.0 do not have reliable ownership records, so the UI marks them Rollback unavailable instead of guessing and risking deletion of pre-existing content.

Duplicate handling

Data Migrator stores source-to-destination mappings so repeat migrations do not blindly create duplicate content.

For Users, the importer can update or skip an existing account. Identity-conflict protection prevents an unsafe merge when the source username and source email independently match different destination accounts.

For Products, Posts, and Pages, mappings allow future runs to update previously migrated records according to the selected duplicate strategy. Products can additionally match an existing non-variation destination product by SKU when no Data Migrator mapping exists.

Installation

  1. Install and activate Data Migrator on both WordPress websites.
  2. On the old website, go to Data Migrator → Settings and choose Source or Both.
  3. Create a WordPress Application Password for the account Data Migrator will use.
  4. Use an administrator account when migrating Users. If migrating Products, activate WooCommerce on both websites.
  5. On the new website, choose Destination or Both.
  6. Open Data Migrator → Import Data.
  7. Enter the source URL, username, and Application Password.
  8. Click Save & Connect.
  9. Select Users, Products, Posts, Pages, or a combination.
  10. Configure the relevant filters/options and click Create migration job.

For maximum throughput on a local-development destination, keep the live migration page open while the job runs.

Rollback is different: once queued, rollback processing runs in the background and does not require the Migration History modal or browser tab to remain open. Action Scheduler is used when available, otherwise WordPress Cron processes rollback batches.

Read the full README on GitHub →