Blog

WordPress Automation: Step-by-Step Breakdown of a Staging-to-Production Deployment Script for WooCommerce

Introduction

Deploying WordPress sites from a staging environment to a live production site can be tricky, especially when running WooCommerce stores. The challenge lies in pushing updates without overwriting critical live data like WooCommerce orders. To tackle this, we’ll break down a powerful bash script that automates this process, preserving order history and handling database data safely while syncing files and settings.

When automating deployments, expect some challenges or unpredictability when synchronizing data between staging and production environments. This script is designed to minimize these issues and help ensure a smoother transition.

This post walks you through the script’s workflow, explaining each step so you can understand how it maintains your production website’s integrity during deployment. You can also just checkout the GitHub repository of the deployment script if you prefer.

Script Overview

This bash script, wordpress-deploy.sh, is designed for a smooth push from staging to production. It automates:

  • Rsync of files (themes, plugins, media files) without overwriting sensitive configs
  • Database migration while preserving WooCommerce orders (supports both legacy CSV and HPOS table exports)
  • Optional handling of Gravity Forms entries
  • URL search-replace to update staging URLs to production URLs
  • Cache clearing feature for popular caching plugins
  • Maintenance mode feature to prevent user activity during deploy

It expects SSH key access, passwordless login for the deploy user, and tools like WP-CLI, mysqldump/mysql, and mailx installed on relevant hosts.

Step 1: Input Validation and Setup

The script begins by checking if a site domain argument is provided. If not, it prints usage instructions and exits. Then it derives a safe site name from the domain for configuration purposes.

site_name= site_name=`echo "$1" |  awk -F "." '{printf "%s\n" ,$1}' | sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' | sed 's/-/_/g' | awk -F. '{str="";if ( length($1) > 16 ) str="";print substr($1,0,15)str""$2}'`

This setup allows per-site dotfiles to supply environment-specific variables, making the script flexible for multiple sites or CI/CD pipelines. Having a detailed deployment plan is essential when managing multiple WordPress sites or integrating with CI/CD pipelines, as it helps ensure version control and smooth code updates to live environments.

Step 2: Pre-flight Check on Staging

Before any changes, the script runs a quick WP-CLI command on staging to verify the WordPress environment is healthy.

check_staging_health=ssh -l $staging_user $staging_host “${wp_cli_staging} –path=”${source_dir}” eval ‘echo ”OK”;’ 2>&1

sanity_check $? “Pre-flight check failed on staging : $check_staging_health”

This pre-flight check is a crucial step in the development workflow, ensuring the staging environment is ready for deployment and minimizing risks when pushing changes to production.

If this check fails, the script aborts and sends an alert email, preventing faulty deploys.

Step 3: Enable Maintenance Mode on Production

To avoid user interference during deployment, the script switches the live site into maintenance mode by renaming the maintenance HTML file.

ssh -l $destination_user $destination_host “cd $destination_dir; mv maintenance_off.html maintenance_on.html”

How would this even work? Well in nginx we have a simple check that looks for this particular file and returns a 503 error if its present :

    # maintenance mode
    if (-f $document_root/maintenance_on.html) {
        return 503;
    }

Then if a 503 is ever received , we have another nginx configuration directive that shows the maintenance_on.html file statically if its present :

    # maintenance
    error_page 503 @maintenance;
    location @maintenance {
        rewrite ^(.*)$ /maintenance_on.html break;
    }

This ensures customers can’t place orders or interact with the site while the database and files are being updated.

Note: Do not forget to enable maintenance mode before starting critical updates. This step is essential to prevent customer activity and ensure the integrity of your WordPress automation process.

Step 4: Sync Files from Staging to Production

Using rsync over SSH, the script transfers files such as themes, plugins, and uploads from staging to production. It excludes sensitive files like wp-config.php and maintenance pages to avoid overwriting production-specific settings.

rsync –exclude=’wp-config.php’ –exclude=’.htaccess’ –exclude=’gravity_forms’ –exclude=’maintenance_on.html’ –exclude=’maintenance_off.html’ –delete …

Any files that exist on production but not on staging will be deleted during the sync, ensuring both environments match exactly.

This step keeps the production website’s custom configurations intact while updating code and media files.

Step 5: WooCommerce Order-Safe Database Migration

If WooCommerce is enabled, the script takes special care to preserve live order data. It is specifically designed to handle differences between staging and production databases, ensuring WooCommerce orders remain consistent and secure during migration.

5a: Backup Production Database

Before any database changes, it creates a compressed backup of the production database as a safety net.

mysqldump ... | gzip > ${prod_db_backup_dir}/${prod_db_name}_${currentdate}.sql.gz

5b: Export WooCommerce Orders

Depending on whether the store uses WooCommerce’s High-Performance Order Storage (HPOS), the script exports order data differently.

  • For HPOS-enabled stores, it exports core WooCommerce order tables separately, avoiding primary key conflicts during import. It also exports order protection data using a WP-CLI command.
  • For legacy stores, it exports all orders to a CSV file using the shift8wcpush WP-CLI extension.

5c: Handle Gravity Forms Entries (Optional)

If enabled, the script exports Gravity Forms entries from production and clears them on staging to avoid duplication.

5d: Clean Orders from Staging (Legacy WooCommerce)

For non-HPOS stores, it deletes all WooCommerce orders and refunds from staging to prevent conflicts during the database push.

5e: Dump Staging Database Excluding WooCommerce Orders

The script dumps the staging database but excludes WooCommerce order tables to ensure live orders on production remain untouched.

mysqldump ... --ignore-table=...wp_wc_orders ... > sqltmp.sql

5f: Transfer Staging Database to Production

The filtered staging database dump is streamed to the production MySQL server, updating everything except WooCommerce orders.

5g: Restore Gravity Forms Entries (Optional)

If Gravity Forms entries were exported earlier, they are imported back into production.

5h: Import WooCommerce Orders Back to Production

  • For HPOS, it imports the previously exported order tables and protection data.
  • For legacy WooCommerce, it imports the CSV orders backup.

5i: Run WordPress Cron and Action Scheduler on Production

To finalize, the script triggers WordPress scheduled tasks to ensure all background jobs run with the updated data.

Step 6: Standard Database Push (Non-WooCommerce Sites)

If WooCommerce is not enabled, the script simply dumps and transfers the entire staging database to production. It can optionally restart the Galera cluster on production to avoid database flow control issues.

Step 7: URL Search-Replace

After database import, the script runs WP-CLI search-replace commands to update all instances of the staging site URL to the production site URL, handling encoded and plain versions.

wp search-replace "staging_url" "production_url" --all-tables --precise

This ensures all links and references point correctly to the live environment. But what about encoded URLs? Many page builders will encode URLs like https%3A%2F%2Fwww.reddit.com. This was the source of many headaches and “gotchya” moments throughout the development of this script. We want to search/replace all regular URls but if a page builder has an image reference to the old url and its encoded, we want to catch that as well.

Step 8: Cache Clearing

If enabled, the script clears caches for popular WordPress caching plugins like WP Rocket and FlyingPress, then regenerates caches to serve fresh content.

Step 9: Disable Maintenance Mode

Finally, the script disables maintenance mode by renaming the maintenance HTML file back, opening the site to users.

mv maintenance_on.html maintenance_off.html

Step 10: Completion Notification

An email notification is sent confirming the successful completion of the deployment.


Conclusion

This script exemplifies how WordPress automation can streamline staging-to-production deployments, especially for WooCommerce sites where preserving order history and customer data is crucial. By carefully sequencing file syncs, database migrations, and maintenance mode toggling, it minimizes downtime and risk.

If you manage WooCommerce stores or complex WordPress sites, adopting a similar approach can save time, reduce errors, and keep your live site stable during updates.

For users interested in alternative solutions, WP Staging is a popular plugin that automates the creation, management, and deployment of staging sites, including features like database synchronization and site cloning for development and testing.

Video tutorials are available online to visually guide you through the deployment process and help you better understand each step.

For more details, you can explore the full script at https://github.com/stardothosting/wordpress-deploy-automation.

Frequently Asked Questions