{"id":356515,"date":"2026-08-22T01:10:18","date_gmt":"2026-08-22T01:10:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/flexa-site-migrator\/"},"modified":"2026-08-22T06:45:24","modified_gmt":"2026-08-22T06:45:24","slug":"flexa-site-migrator","status":"publish","type":"plugin","link":"https:\/\/ja.wordpress.org\/plugins\/flexa-site-migrator\/","author":23412324,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.6","stable_tag":"1.0.6","tested":"7.1","requires":"6.2","requires_php":"7.0","requires_plugins":null,"header_name":"Flexa Site Migrator - WordPress Migration & Staging","header_author":"flexatech","header_description":"Creates a package (files + database + installer) to migrate WordPress from production to staging. Runs anywhere, no shell required.","assets_banners_color":"63a6d6","last_updated":"2026-08-22 06:45:24","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":51,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.4":{"tag":"1.0.4","author":"flexatech","date":"2026-08-22 01:10:02"},"1.0.6":{"tag":"1.0.6","author":"flexatech","date":"2026-08-22 06:45:24"}},"upgrade_notice":{"1.0.6":"<p>Stops the build safely if core\/a plugin\/a theme is updated mid-build \u2014 previously this silently produced a corrupt package that could fatal the migrated site.<\/p>","1.0.5":"<p>Moves the plugin to its own top-level Site Migrator menu with Export and Import submenus.<\/p>","1.0.4":"<p>Confirms compatibility with WordPress 7.1 and documents the plugin&#039;s external network request in the readme.<\/p>","1.0.3":"<p>Locks down the package storage directory against direct web access, stops shipping runnable PHP files into uploads, and moves all database work to $wpdb-&gt;prepare().<\/p>","1.0.2":"<p>Renames the plugin to Flexa Site Migrator, prefixes all identifiers to avoid collisions, and hardens database queries against identifier injection.<\/p>","1.0.1":"<p>Adds a pre-migration system check, one-click cleanup, and single-zip package download; fixes database import on MySQL 5.7+\/8.0 and installer.php downloads.<\/p>","1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3660065,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3660065,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3660065,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3660065,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.4","1.0.6"],"block_files":[],"assets_screenshots":{"screenshot-1.jpg":{"filename":"screenshot-1.jpg","revision":3660065,"resolution":"1","location":"assets","locale":"","width":1170,"height":658},"screenshot-2.jpg":{"filename":"screenshot-2.jpg","revision":3660065,"resolution":"2","location":"assets","locale":"","width":1170,"height":658},"screenshot-3.jpg":{"filename":"screenshot-3.jpg","revision":3660065,"resolution":"3","location":"assets","locale":"","width":1170,"height":658},"screenshot-4.jpg":{"filename":"screenshot-4.jpg","revision":3660065,"resolution":"4","location":"assets","locale":"","width":1170,"height":658},"screenshot-5.jpg":{"filename":"screenshot-5.jpg","revision":3660065,"resolution":"5","location":"assets","locale":"","width":1170,"height":658},"screenshot-6.jpg":{"filename":"screenshot-6.jpg","revision":3660065,"resolution":"6","location":"assets","locale":"","width":1170,"height":658}},"screenshots":{"1":"Build the migration package on the production site (Site Migrator \u2192 Export) \u2014 the database and files are exported in chunks with live progress.","2":"Pull from production via link \u2014 paste the pull link on staging (Site Migrator \u2192 Import), test the connection, and start the migration.","3":"Automatic migration in progress on staging \u2014 the package is downloaded, extracted, and the database imported with search-replace, all in one run.","4":"Standalone installer \u2014 the system check verifies PHP, required extensions, archive parts, and the database connection before anything is touched.","5":"Standalone installer \u2014 enter the staging database details, table prefix, new site URL, and directory path.","6":"Migration complete \u2014 a one-click cleanup deletes installer.php, the archives, database.sql, and manifest.json for security."}},"plugin_section":[],"plugin_tags":[151,2814,9055,4155,19979],"plugin_category":[59],"plugin_contributors":[255540],"plugin_business_model":[],"class_list":["post-356515","plugin","type-plugin","status-publish","hentry","plugin_tags-backup","plugin_tags-clone","plugin_tags-duplicate","plugin_tags-migration","plugin_tags-staging","plugin_category-utilities-and-tools","plugin_contributors-flexatech","plugin_committers-flexatech"],"banners":{"banner":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/banner-772x250.png?rev=3660065","banner_2x":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/banner-1544x500.png?rev=3660065","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/icon-128x128.png?rev=3660065","icon_2x":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/icon-256x256.png?rev=3660065","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/screenshot-1.jpg?rev=3660065","caption":"Build the migration package on the production site (Site Migrator \u2192 Export) \u2014 the database and files are exported in chunks with live progress."},{"src":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/screenshot-2.jpg?rev=3660065","caption":"Pull from production via link \u2014 paste the pull link on staging (Site Migrator \u2192 Import), test the connection, and start the migration."},{"src":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/screenshot-3.jpg?rev=3660065","caption":"Automatic migration in progress on staging \u2014 the package is downloaded, extracted, and the database imported with search-replace, all in one run."},{"src":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/screenshot-4.jpg?rev=3660065","caption":"Standalone installer \u2014 the system check verifies PHP, required extensions, archive parts, and the database connection before anything is touched."},{"src":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/screenshot-5.jpg?rev=3660065","caption":"Standalone installer \u2014 enter the staging database details, table prefix, new site URL, and directory path."},{"src":"https:\/\/ps.w.org\/flexa-site-migrator\/assets\/screenshot-6.jpg?rev=3660065","caption":"Migration complete \u2014 a one-click cleanup deletes installer.php, the archives, database.sql, and manifest.json for security."}],"raw_content":"<!--section=description-->\n<p>Flexa Site Migrator migrates a WordPress site from <strong>production to staging<\/strong>. It builds a package made of one or more <code>archive-*.zip<\/code> files (site files, split automatically), a <code>database.sql<\/code> dump, and a standalone <code>installer.php<\/code>. It works whether staging is on the same server or a different one, and <strong>requires no shell\/SSH access<\/strong> \u2014 everything runs through the WordPress admin over regular HTTP.<\/p>\n\n<p><strong>Key features<\/strong><\/p>\n\n<ul>\n<li><strong>Chunked build<\/strong> \u2014 the database is exported in chunks (using <code>mysqldump<\/code> when available, otherwise pure PHP) and files are compressed in chunks to avoid timeouts.<\/li>\n<li><strong>Three ways to deploy to staging<\/strong> \u2014 pull-by-link, wp-admin import, or a standalone installer for empty sites.<\/li>\n<li><strong>Serialize-safe search-replace<\/strong> \u2014 URLs are updated with a recursive unserialize \u2192 replace \u2192 re-serialize algorithm, so serialized options\/widgets never get corrupted.<\/li>\n<li><strong>Handles large sites<\/strong> \u2014 the build is fully chunked and files are split into ~200MB archive parts; the database deploy runs in a single request (check the System check panel for your PHP limits before importing very large databases).<\/li>\n<li><strong>Token-protected transfers<\/strong> \u2014 pull links carry an SHA-256 hashed token (only the hash is stored on the server), with optional password and IP allowlist restrictions.<\/li>\n<\/ul>\n\n<p><strong>Deployment methods<\/strong><\/p>\n\n<p><em>Method A \u2014 Pull via link (simplest):<\/em> Install the plugin on both production and staging. Build the package on production, copy the link, paste it on staging under Site Migrator \u2192 Import, and click Pull &amp; Migrate. Staging downloads the files from production (byte-range supported) and runs extraction, DB import, and search-replace on its own.<\/p>\n\n<p><em>Method B \u2014 wp-admin import:<\/em> Copy the package folder to staging's <code>wp-content\/flexasm-packages\/<\/code>, then run the migration from Site Migrator \u2192 Import.<\/p>\n\n<p><em>Method C \u2014 Standalone installer:<\/em> For an empty staging site with no WordPress. Upload <code>installer.php<\/code> and the package files to the site root, open <code>installer.php<\/code> in a browser, enter the database details, and start the migration.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin does not connect to any service operated by us or by a fixed third party, and it sends no data anywhere on its own.<\/p>\n\n<p>The only outbound network request it makes is to the <strong>production site URL you paste on the staging side<\/strong> (Site Migrator \u2192 Import \u2192 \"Pull from production via link\"). When you click Test connection or Pull &amp; Migrate, staging contacts that URL to download the migration package (site files and the database dump) you created on production. The request carries the access token from the link, and, if the package is password-protected, the password you enter (sent in a request header). No third party is involved \u2014 both ends are your own sites \u2014 and nothing is transmitted until you paste a link and start a pull.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>flexa-site-migrator<\/code> folder to <code>\/wp-content\/plugins\/<\/code> on the <strong>production<\/strong> site (or install it through Plugins \u2192 Add New \u2192 Upload Plugin).<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> menu in WordPress.<\/li>\n<li>Go to <strong>Site Migrator \u2192 Export<\/strong> to build a package.<\/li>\n<li>To deploy via link or wp-admin import, install and activate the plugin on the <strong>staging<\/strong> site as well, then use <strong>Site Migrator \u2192 Import<\/strong>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20require%20ssh%20or%20wp-cli%3F\"><h3>Does it require SSH or WP-CLI?<\/h3><\/dt>\n<dd><p>No. The whole build and import process runs inside the WordPress admin over normal HTTP requests.<\/p><\/dd>\n<dt id=\"will%20i%20get%20logged%20out%20after%20importing%20on%20staging%3F\"><h3>Will I get logged out after importing on staging?<\/h3><\/dt>\n<dd><p>Possibly. After the database is overwritten, the users table belongs to production, so you may need to log back in with a production account.<\/p><\/dd>\n<dt id=\"does%20it%20handle%20multi-gigabyte%20databases%3F\"><h3>Does it handle multi-gigabyte databases?<\/h3><\/dt>\n<dd><p>The build side is fully chunked, so exporting is safe at any size. The import on staging runs in a single request through wp-admin; for very large databases, check the System check panel and raise <code>max_execution_time<\/code>\/<code>memory_limit<\/code> in php.ini first, or use the standalone installer (Method C).<\/p><\/dd>\n<dt id=\"is%20the%20transfer%20secure%3F\"><h3>Is the transfer secure?<\/h3><\/dt>\n<dd><p>Pull links carry an SHA-256 hashed token \u2014 only the hash is stored on production, and the real token stays in the link. You can additionally protect a package with a password and restrict it to specific IP addresses. Always delete the package after the migration is complete.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20staging%20site%3F\"><h3>What happens to my staging site?<\/h3><\/dt>\n<dd><p>Staging is <strong>completely overwritten<\/strong> (files and database). Only use it with a staging site you can safely throw away.<\/p><\/dd>\n<dt id=\"is%20it%20translation-ready%3F\"><h3>Is it translation-ready?<\/h3><\/dt>\n<dd><p>Yes. All admin-facing strings (PHP and JavaScript) are internationalized under the <code>flexa-site-migrator<\/code> text domain, and a <code>languages\/flexa-site-migrator.pot<\/code> template is included.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.6<\/h4>\n\n<ul>\n<li>Fix: the build now stops immediately with a clear message if WordPress core, a plugin, or a theme is updated on the source site while the package is being built. Previously the chunked build silently produced a torn package that mixed files from two versions (new files missing, removed files still present), which could fatal the migrated site.<\/li>\n<li>Change: WordPress automatic updates are held off while a package build is in progress (released as soon as the build finishes, or within ~15 minutes if a build is abandoned).<\/li>\n<li>Security: the mysqldump fast-path now passes the database password via the environment instead of the command line, so it is no longer visible in the server process list while the dump runs.<\/li>\n<li>Fix: bundled translations in <code>\/languages<\/code> are now loaded (<code>load_plugin_textdomain<\/code>), so translations work outside WordPress.org distribution too.<\/li>\n<\/ul>\n\n<h4>1.0.5<\/h4>\n\n<ul>\n<li>Change: the plugin now has its own top-level admin menu <strong>Site Migrator<\/strong> (with <strong>Export<\/strong> and <strong>Import<\/strong> submenus) instead of living under Tools.<\/li>\n<\/ul>\n\n<h4>1.0.4<\/h4>\n\n<ul>\n<li>Compatibility: tested up to WordPress 7.1.<\/li>\n<li>Docs: added an \"External services\" section documenting the pull request to the production URL you provide (no third-party service is contacted).<\/li>\n<\/ul>\n\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>Security: package storage under <code>uploads\/flexasm-packages<\/code> now denies ALL direct web access (deny-all <code>.htaccess<\/code>); archives, <code>database.sql<\/code> and <code>manifest.json<\/code> are streamed through authenticated admin-ajax endpoints (capability + nonce) or the hashed-token pull endpoint instead of direct URLs.<\/li>\n<li>Security: <code>installer.php<\/code> is no longer written into the uploads directory \u2014 it is streamed on demand straight from the plugin's template, so no runnable PHP file ever lives in uploads.<\/li>\n<li>Security: removed the standalone <code>runner.php<\/code> chunked-import mechanism (a web-executable PHP file in uploads); the database deploy always runs through the authenticated wp-admin AJAX request.<\/li>\n<li>Change: all database work in the plugin now goes through <code>$wpdb<\/code> with <code>prepare()<\/code> \u2014 the direct <code>mysqli_*<\/code> calls were removed from the exporter, importer, and search-replace, and table\/column identifiers are bound with the <code>%i<\/code> placeholder.<\/li>\n<li>Change: the minimum supported WordPress version is now 6.2 (required for the <code>%i<\/code> identifier placeholder in <code>$wpdb-&gt;prepare()<\/code>).<\/li>\n<li>Fix: the file archiver now excludes the package storage directory at its real (uploads-based) location, so packages no longer get zipped into themselves.<\/li>\n<li>Fix: a build or import no longer aborts when a single AJAX request drops \u2014 chunked requests are retried up to 3 times with backoff, the pull download writes each chunk at its explicit offset so a retry can never duplicate bytes, and connection errors now report the HTTP status code.<\/li>\n<li>Change: the standalone installer now disables its buttons and shows a spinner with a busy label while a step is running (the migration step runs in a single request and can take minutes), preventing double submits. Steps are submitted with fetch() so the page \u2014 and the busy indicator \u2014 stays visible while waiting, in every browser (a slow full-page POST would blank the page in Safari).<\/li>\n<li>Fix: after a successful pull deletes a package's migration files from production (automatic cleanup), the package list now says so instead of offering downloads \u2014 the .zip download, pull link and pull endpoint all return a clear \"create a new package\" message rather than an installer-only zip. Leftover directories from cleaned-up or unfinished builds are now listed and can be deleted from the UI.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Change: renamed the plugin to <strong>Flexa Site Migrator<\/strong> (slug <code>flexa-site-migrator<\/code>) for a distinctive, non-generic name.<\/li>\n<li>Change: prefixed all globals, constants, options, AJAX actions, script\/style handles, and nonces with <code>flexasm_<\/code>\/<code>FLEXASM_<\/code> under the <code>Flexa\\SiteMigrator<\/code> namespace to avoid collisions.<\/li>\n<li>Security: hardened database export, import, and search-replace queries \u2014 table and column identifiers are now backtick-escaped, closing an identifier-interpolation gap.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>New: manual installer now runs a system requirements check (files present, database connection, PHP extensions) before starting a migration.<\/li>\n<li>New: one-click cleanup of the migration files (installer, archives, database dump, manifest) from the success screen after migrating.<\/li>\n<li>New: download an entire package as a single .zip, in addition to downloading each file separately.<\/li>\n<li>Fix: database import could fail on MySQL 5.7+\/8.0 with \"Invalid default value\" on legacy zero-date columns (e.g. WooCommerce ActionScheduler).<\/li>\n<li>Fix: downloading installer.php could fail on servers that block direct access to PHP files under uploads; it is now served safely through the admin.<\/li>\n<li>Change: removed the \"Remove plugin from the source site\" button \u2014 uninstall the plugin on the source site manually.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Migrate WordPress from production to staging with no shell access. Creates a package (files + database + installer) that runs anywhere.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/356515","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=356515"}],"author":[{"embeddable":true,"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/flexatech"}],"wp:attachment":[{"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=356515"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=356515"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=356515"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=356515"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=356515"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ja.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=356515"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}