The rule
Nothing untested touches a store that is taking money. Not a plugin update, not a theme tweak, not a shipping rule. The store is a cash register; you do not open it up while a customer is paying to see what happens.
That rule is easy to state and routinely broken, because the tooling to follow it takes a day to set up and nobody set it up. Here is the setup, and the routine that uses it.
The staging copy
A staging store is a full copy of production, files and database, at a private address, on the same hosting stack and PHP version. It differs from production only in three ways, all deliberate:
- Payment gateways in test mode, with sandbox keys. Real cards must never be charged from staging.
- Outgoing email disabled or redirected to a test inbox, so no customer receives a "your order has shipped" from a rehearsal.
- Search engines blocked, so staging is never indexed.
Refresh it from production before every testing session, so you are testing against today's products, orders and settings. Most managed hosts do this in one click; otherwise a WP-CLI script exports, imports and search-replaces the URL in a few minutes.
Do not let staging drift into a second development site with its own history. It is a disposable mirror.
Gateway sandboxes
Every serious gateway has a test mode: Stripe, PayPal, Square, Mollie, Adyen. Configure staging with test keys and use the gateway's documented test card numbers to exercise success, decline, 3D Secure challenge and refund. Check that the webhook endpoint for staging points at staging, not production; a staging webhook configured against the production endpoint will move real orders.
Test the whole path, not just the payment: order created, status transitions, stock reduced, emails generated (to the test inbox), and the order visible in the gateway's test dashboard.
The pre-deploy test list
Before any change goes to production, on refreshed staging with the change applied:
- Home, a category, a product, the cart, the checkout load and look right, on a phone.
- Add to cart for a simple product and a variable product.
- Checkout with each enabled gateway using a test card, including one 3D Secure challenge.
- Shipping rates appear for a domestic and an international address, and a coupon applies.
- Order status moves to Processing without manual intervention. Stock reduces.
- Emails for the order arrive in the test inbox and read correctly.
- Refund one order from the admin; the gateway reflects it.
- Admin: order search, bulk status update, and the Analytics dashboard still load.
- The change itself does what it was meant to.
- The error log is clean.
For a plugin update this takes twenty minutes. For a theme change, longer. Skip it once and you learn why it exists.
Deploying
Code changes go via version control and an atomic deploy, so the switch to the new version is instant and reversible. Plugin updates go through the same mechanism if plugins are Composer-managed, or are applied on production only after passing on staging, in the same order.
Deploy at a quiet time for the store. Not Friday afternoon, not during a sale, not while a campaign email is landing.
The rollback path
Before deploying, know exactly how to undo it:
- Code: switch the release symlink back, or revert the commit and redeploy. Under a minute.
- Plugin update: the previous version's zip, kept, or the Composer lock reverted.
- Database: the on-demand backup taken immediately before the deploy. Restoring it loses any orders placed since, so the window between backup and deploy should be minutes, and the decision to restore the database is the last resort, not the first.
- Settings changes: written down before changing, so they can be reversed by hand.
If you cannot state the rollback in one sentence, do not deploy.
After deploying
Place a real, low-value order on production with a real card. Confirm it processes end to end. Watch the error log and the gateway's webhook log for an hour. Then refund your test order.
Why this is the job
Most WooCommerce emergencies we are called to are the result of a change made directly on production: a plugin updated from the admin, a snippet pasted into the theme, a gateway setting changed to see if it helped. The store broke, and there was no way back except guessing.
Staging, sandboxes, the test list and a rollback path are not overhead. They are what makes it possible to change a store at all without betting the day's revenue. They are how every piece of WooCommerce work we do ships, and they are the first thing we set up on a store that joins a care plan, before the first update is touched.