WP Manifestindependent plugin directory
manifest / utilities / universal-site-migration

Universal Site Migration

A WordPress plugin which helps to import, export and migrate the whole WordPress website including the WordPress files, database and passwords

by mukundvashisht · github.com/mukundvashisht/universal-site-migration

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/mukundvashisht/universal-site-migration/archive/refs/heads/master.zip

Universal Site Migration 0.2.0

A self-contained WordPress plugin for exporting and importing a site. It uses your existing WordPress administrator account. There is no service account, subscription, activation key or external API.

Install and use

  1. In WordPress, open Plugins → Add New Plugin → Upload Plugin.
  2. Select universal-site-migration.zip, install it and activate it.
  3. Open Site Migration → Export site. Keep the page open. When complete, download the backup ZIP.
  4. On the destination, install the same WordPress version and this plugin.
  5. Open Site Migration, choose your backup ZIP, acknowledge replacement and click Import site.
  6. After completion, sign in using the source site's username and password. Open Settings → Permalinks → Save Changes to regenerate the destination's rewrite rules. Test the site's forms, checkout and integrations.

Only version 0.2.0 (usm-2) backups are supported. Re-export the original site with this release; the original prototype's 0.1.0 archives use a different format.

What is included

  • WordPress files under the installation directory: core, plugins, themes, uploads, MU plugins, languages and custom files.
  • All database tables belonging to the site's WordPress table prefix, including plugin tables.
  • Users, password hashes, roles, posts, options and metadata.
  • Binary database values, Unicode, nested serialized data and serialized objects without constructing those objects during replacement.
  • Automatic source URL and installation-path replacement in text data. Post GUIDs and password hashes are preserved.

The destination keeps its database credentials, table prefix and configured home/site URLs. Configuration files (wp-config.php, .htaccess, web.config, .user.ini, php.ini), the running migration plugin and host cache/database drop-ins are preserved during import. Source copies are in the backup for manual reference. Review any source-specific constants separately; they are not merged into the destination configuration.

Git directories, node_modules, wp-content/cache and migration storage are excluded. PHP dependency directories such as vendor are included. Empty directories are not retained. Files and unrelated destination tables that do not exist in the archive are not deleted.

WordPress sessions and application passwords are invalidated on import. Normal passwords are preserved. Reconnect external services where necessary; hosting, DNS, mailboxes, SSL certificates and third-party account configuration are outside a WordPress archive.

Requirements and supported scope

  • PHP 8.1 or later, with ZIP and the normal WordPress database extensions.
  • A standard, single-site WordPress installation with wp-content and plugins at their default locations.
  • Matching WordPress versions on source and destination.
  • InnoDB site tables; database access to create, insert, update, rename and drop tables.
  • Enough disk space for the ZIP, extracted files and recovery copies, plus database space for temporary and retained tables.
  • Write access to the WordPress files being replaced.

Multisite, shared/custom user tables, custom database drop-ins, symbolic links, database views/triggers, external table storage and custom PHP Serializable payloads requiring URL changes are not supported. The plugin fails with a message when detected. Custom plugin table schemas and environment-specific MU plugins still require staging validation. No software can guarantee every host or third-party plugin combination; test on staging before replacing a production site.

Use a fresh destination where possible. Pause source edits, comments, orders and other writers while exporting. The export uses batches and does not take a transactionally consistent snapshot of a changing live site. Keep the destination unused during import; file promotion spans several requests.

Private storage

By default, backups and recovery files are stored in wp-content/usm-private. Apache and IIS protection files are generated. Before starting a migration, the plugin checks that a test file cannot be downloaded over HTTP.

On Nginx, configure a deny rule for this directory, or use an absolute directory outside the public web root. Add this before WordPress is loaded in wp-config.php:

define('USM_STORAGE_DIR', '/absolute/private/path/wordpress-migrations');

The directory must be writable by PHP and must not be publicly served by another website. If a loopback HTTP check is blocked by your host, private storage outside the web root avoids that check.

Backups contain private data and password hashes. Download them only to trusted storage. Delete unneeded archives and recovery data from the plugin screen.

Interruptions and recovery

  • Reload the migration screen and select Resume after a connection interruption.
  • For an interrupted upload, reselect the same ZIP and select Resume. Uploads use 512 KiB chunks. This avoids a single large upload request but still requires the host to accept each chunk.
  • A failed job displays its actual error. Correct the issue and retry, or discard it. Validation failures must be discarded and restarted.
  • The database imports into temporary tables. Live site tables are switched together only after import and file promotion finish.
  • Before replacing a file, its previous contents are retained. Discard / revert incomplete import restores files already replaced, while retaining the original live database.
  • File promotion is not an atomic whole-site switch. A PHP or hosting failure can make WordPress unavailable before an AJAX recovery request can run. Keep an independent host backup and file/database access available.
  • A completed import retains original tables under its recorded usmo_…_ prefix and original overwritten files in its <job-id>.old directory. State is stored in <job-id>.php under private storage. These are recovery materials, not a one-click rollback of a completed import.
  • Remove recovery data deletes the retained tables and temporary files. Delete backup deletes an export. Both require administrator confirmation.

If WordPress cannot load after an interrupted import, a hosting administrator can restore the originals from <job-id>.old, remove newly created files recorded in <job-id>.journal, and restore the independent host backup as needed. Before database commit, original live tables remain in place. Do not delete recovery data until the migrated site has been checked.

Implementation

  • includes/Engine.php: export, chunk upload, validation, staging, promotion, cancellation and cleanup.
  • includes/Database.php: schema/row handling, serialized replacement and database switch.
  • includes/Storage.php: private storage, request locking and path checks.
  • includes/Plugin.php: administrator page, authenticated AJAX and downloads.
  • assets/: browser controls and styles.

Archive layout: manifest.json, database.jsonl, files.jsonl, and files/…. Database values are base64 encoded in JSON lines; archive contents are checked against SHA-256 hashes. These checks detect corruption, not authorship: only import backups you trust.

Validation

See TEST-REPORT.md for the environments and checks exercised. The serialization/path checks can also be run against a disposable WordPress installation:

php tests/serialization.php /absolute/path/to/wordpress/wp-load.php

Do not point migration integration tests at a production installation.