Push WordPress Staging to Production Without Overwriting Data

by Fahim

Hit your host’s one-click “Push Staging to Live” button on an active store, and you’ll instantly wipe out every WooCommerce order, customer account, and comment made while you were building.

I’ve seen it happen too many times. Here is how I selectively sync theme and plugin files, isolate configuration tables, and pull staging changes into production without touching a single row of live user data.

Close up view of terminal showing WP-CLI selective database migration commands
Close up view of terminal showing WP-CLI selective database migration commands

Why One-Click Staging Sync Breaks Live Sites

Most managed hosting control panels give you a big friendly button that says “Deploy Staging to Live”. Behind the scenes, that button is a sledgehammer: it dumps the entire staging database and overwrites production with it.

If you spent three days tweaking a homepage design on staging, your staging database snapshot is three days old. The second you push that snapshot, every transaction, sign-up, and password reset that happened on live during those three days simply vanishes.

To push staging safely, you have to split your work into two layers: the filesystem (PHP, CSS, JS, media) and the database (content, settings, transactional data). Code and static assets can almost always be synced directly with rsync. The database requires a surgical approach based on what actually changed.

Step 1: Take an Immediate Live Backup

Before touching any files or running SQL queries, take a fresh backup of production over SSH. If you hit an ID conflict or an accidental table drop, you can restore state in seconds.

SSH into your production server, jump into your live web root, and use WP-CLI to dump the database and verify the file archive:

cd /home/u123456789/domains/example.com/public_html # Create a safety database dump
wp db export pre_staging_push_$(date +%Y%m%d_%H%M%S).sql --add-drop-table # Quick archive of wp-content in case of file conflicts
tar -czf wp-content-backup-$(date +%Y%m%d).tar.gz wp-content/

If you haven’t automated this yet, check our guide on how to automate WordPress backups with WP-CLI and Cron to ensure your off-site retention is running reliably.

Step 2: Sync Code and Static Files First

If your staging updates only involved custom theme code, new plugin files, or stylesheets, you do not need to touch the database at all. Keep your code in Git or sync directory changes directly using rsync.

I use rsync with a dry-run flag first so I can inspect modified files before committing, making sure to skip uploads and cache directories:

# Dry run first to verify which files will transfer
rsync -avnc --delete  --exclude='wp-config.php'  --exclude='wp-content/uploads/'  --exclude='wp-content/cache/'  --exclude='.git/'  /home/u123456789/domains/example.com/staging/  /home/u123456789/domains/example.com/public_html/

Once the dry-run output looks clean, strip the -n flag to run the actual sync:

rsync -avc  --exclude='wp-config.php'  --exclude='wp-content/uploads/'  --exclude='wp-content/cache/'  --exclude='.git/'  /home/u123456789/domains/example.com/staging/  /home/u123456789/domains/example.com/public_html/

Check the official rsync manual pages if you need extra flags for bandwidth limits or checksum verification.

Step 3: Understand Safe vs Dynamic Database Tables

When staging updates involve plugin settings, Elementor templates, or new admin options, you have to touch the database. The trick to avoiding data loss is categorizing tables according to the WordPress Database Description.

  • Dynamic / Transactional Tables (NEVER overwrite from staging): wp_users, wp_usermeta, wp_comments, wp_commentmeta, wp_woocommerce_order_items, wp_woocommerce_order_itemmeta, wp_actionscheduler_*, and form tables like wp_fluentform_submissions or wp_gf_entry.
  • Structural / Configuration Tables (Selectively synced): wp_options (specific keys only), theme options, and custom post type definition tables.
  • Content Tables (Require ID reconciliation or partial merge): wp_posts, wp_postmeta, wp_terms, wp_term_taxonomy, wp_term_relationships.

Step 4: Push Isolated Configuration and Custom Tables

If you installed a plugin on staging that created its own standalone tables (like a redirection manager or an analytics logger), you can dump those individual tables from staging and

Export just those specific plugin tables from your staging environment:

cd /home/u123456789/domains/example.com/staging # Export only custom tables created by your plugin
wp db export staging_custom_tables.sql --tables=wp_redirection_items,wp_redirection_groups

Run a search and replace on the exported SQL file to swap out your staging domain before importing it into production:

# Replace staging subdomain with live domain in the isolated dump
sed -i 's/staging.example.com/example.com/g' staging_custom_tables.sql # Import the isolated tables into production
cd /home/u123456789/domains/example.com/public_html
wp db import /home/u123456789/domains/example.com/staging/staging_custom_tables.sql

For deep database updates across full environments, check our walkthrough on how to migrate large WordPress sites with SSH and WP-CLI.

Step 5: Migrate Specific Modified Pages Without Stomping New Posts

If you built new landing pages or redesigned existing ones on staging while writers published blog posts on live, do not overwrite wp_posts. An auto-increment collision will corrupt your relational post IDs.

Instead, use the native WordPress export tool via WP-CLI to export only the specific post IDs you modified on staging, then

Find the post IDs of the revised pages on staging:

cd /home/u123456789/domains/example.com/staging # List recently modified pages
wp post list --post_type=page --fields=ID,post_title,post_modified --posts_per_page=10

Export only those explicit page IDs to an XML file:

# Export pages with IDs 42, 108, and 215
wp export --post_type=page --post__in=42,108,215 --dir=/tmp/

Now jump to your production site and import the file using WP-CLI. Install the WordPress Importer package if it’s missing:

cd /home/u123456789/domains/example.com/public_html # Ensure importer plugin is active
wp plugin install wordpress-importer --activate # Import the staging export XML
wp import /tmp/example-pages.xml --authors=mapping.csv

Check the official WP-CLI commands documentation for extra flags around author mapping and attachment downloads.

Step 6: Sync Plugin and Theme Settings Safely in wp_options

The wp_options table holds both environment-specific settings (like siteurl, home, mail credentials) and design configurations (like theme_mods_mytheme or page builder global JSON).

Never overwrite the entire wp_options table. Instead, read the specific option value from staging and apply it to production:

# Get raw serialized theme configuration from staging
THEME_MODS=$(wp --path=/home/u123456789/domains/example.com/staging option get theme_mods_astra --format=json)
# Set the exact configuration on production without breaking site URLs
wp option update theme_mods_astra "$THEME_MODS" --format=json

This approach prevents production’s siteurl and home options from reverting back to your staging subdomain, which avoids instant redirect loops and SSL mismatch errors. If your asset URLs get crossed, read our guide on how to fix SSL mixed content in WordPress with WP-CLI.

Step 7: Clear Object Cache and Transients

After pushing code and selective database rows, WordPress might still serve stale query results from Redis or memory cache.

Flush the object cache, drop expired transients, and rebuild rewrite rules using WP-CLI:

cd /home/u123456789/domains/example.com/public_html # Flush memory cache
wp cache flush # Delete all transient options
wp transient delete --all # Regenerate rewrite rules for clean permalinks
wp rewrite flush --hard

If you’re running an in-memory datastore, check our tutorial on how to configure Redis object cache for faster WordPress to ensure your cache invalidation works as expected.

Gotchas to Avoid During Staging Pushes

  • Serialized Data in Custom Fields: Avoid standard SQL REPLACE() statements for updating URLs in wp_postmeta. PHP serialized strings track byte length (e.g., s:19:"staging.example.com"). Modifying the string without updating that integer corrupts the data. Always use wp search-replace.
  • Attachment ID Mismatches: If you upload images to staging and manually link their media IDs in live post content, the IDs won’t match. Use the native XML export/import so media files get registered with proper IDs in the live media library.
  • Staging Cron Jobs: Make sure your staging site has DISABLE_WP_CRON enabled or uses dummy email addresses so background tasks don’t fire duplicate transactional emails to real customers while you test.

Frequently Asked Questions

Can I use plugins like WP Migrate DB Pro for this?

Yes. WP Migrate DB Pro (now WP Migrate) lets you run selective table migrations, custom search-and-replace profiles, and exclude specific post types. It is one of the few GUI tools that handles partial database syncs without trashing live tables.

What happens if a new WooCommerce order comes in mid-migration?

Because you’re syncing code via rsync and updating options via targeted WP-CLI commands rather than importing a full database dump, live database operations like WooCommerce checkouts and payment webhooks continue uninterrupted.

How do I push Elementor site settings without overwriting live posts?

Elementor stores global styles and kit settings under the elementor_active_kit post ID in wp_posts and specific keys in wp_options. Export the Elementor Kit via Elementor > Tools >

Import / Export Kit, then import that kit zip file on the live site.

Why did my site show a database error immediately after syncing files?

This happens when newly deployed PHP code calls a database column or plugin table that hasn’t been migrated yet. Always run your database schema updates and table syncs before running the final file rsync.

Next Steps

Now that your deployment workflow is isolated and safe, check our guide on how to set up a WordPress staging site in Hostinger hPanel to create a clean sandbox environment that mirrors your live stack.

all_in_one_marketing_tool