WooCommerce field notes
Fix WooCommerce, Subscriptions, and Stripe problems with a script
A working library of the problems that hit real WooCommerce stores, across WooCommerce, WooCommerce Subscriptions, and the Stripe gateway, and how to detect or repair each one with a small Python or Node.js script. Every guide has a diagram of the problem, a diagram of the fix, full code in both languages, tests, and links to the source reports.
Order status and webhooks
7 guidesPaid orders stuck on Pending payment
The Stripe charge went through but the order never moved. Find the lost webhook and finish the order.
ReconcilerWebhook cannot match the order
Orders without the intent or charge ID saved, so Stripe cannot find them. Recover and backfill the ID.
RepairWebhook never delivered
Wrong endpoint or missing events, so no order ever updates. Check the endpoint and the events it listens to.
DiagnosticWebhook signing secret mismatch
Every event is rejected because the stored secret is wrong or from the other mode. Spot it fast.
DiagnosticWebhook API version mismatch
The charges array is gone in newer API versions. Read latest_charge instead and stop dropping orders.
soonReplay missed webhook events
The site was down past the retry window. Pull the events you missed and apply them in order.
ReconcilerDuplicate webhook events
The same event ran twice and left double notes. Keep a ledger of event IDs and skip repeats.
soonPayment lifecycle
7 guidesOrders stuck on 3D Secure
The buyer never finished the bank step, so the PaymentIntent sits in requires_action. Sweep and resolve.
ReconcilerAuthorized charges never captured
Manual capture orders left on hold until the hold expires. Capture the valid ones before you lose them.
ReconcilerDeclined card stuck on Pending
A failed card leaves the order pending instead of failed, so stock stays locked. Move it to failed.
RepairClean up abandoned PaymentIntents
Half finished checkouts pile up and skew your numbers. Cancel the ones that will never complete.
ReconcilerSlow methods succeed but never match
SOFORT or Klarna confirm later and the order never catches up. Match the late charge to its order.
soonLate failure reverts a paid order
An out of order failed event flips a good order back to failed. Trust Stripe as the source of truth.
ReconcilerOrder marked paid with no charge
An order looks paid but Stripe has no matching charge. Flag it before it counts as real revenue.
DiagnosticCharges and money
6 guidesDouble charge from a race
The redirect and the webhook both complete the order and charge twice. Find and refund the extra.
ReconcilerIdempotency gap on PaymentIntents
A retry without an idempotency key made a second charge. Detect the duplicates and clean them up.
soonZero decimal currency charged 100x
Yen and similar currencies got multiplied by 100. Catch the overcharge and refund the difference.
soonAmount does not match the order
The captured amount and the order total disagree. Compare them and report the ones that drift.
soonPartial capture total mismatch
A partial capture but the order still shows the full amount. Line the total up with what was taken.
soonPartial refund gives back everything
A small refund returned the whole charge. Spot the over refund on externally captured orders.
soonRefunds and disputes
6 guidesDashboard refund not synced
A refund made in Stripe never reached WooCommerce, so the order still looks paid. Record it back.
ReconcilerRefund skips non card methods
Refunds on iDEAL or EPS never flip the order to refunded. Fix the ones the webhook missed.
RepairFee and net stale after a refund
The saved fee and net still show the pre refund total. Recompute them from the balance transaction.
RepairDisputes not recorded on the order
A chargeback pulled funds but the order shows nothing. Put the dispute state on the order.
soonRefund and dispute double reversal
A refunded charge got disputed and Stripe pulled the money twice. Measure the loss you never booked.
soonFee and net missing on renewals
Renewal orders stopped saving fee and net after an update. Backfill them for clean books.
soonFees, payouts, and accounting
3 guidesRecord Stripe fees on orders
Reports show list price, not what you kept. Save the fee and net so profit is real.
soonMatch payouts to orders
A bank deposit never equals the order totals. Build a per payout report that ties out to the cent.
soonPresentment vs settlement currency
The buyer paid one currency and you settled another. Make the exchange explicit in your report.
soonCustomers, cards, and tokens
7 guidesDuplicate customers for one email
Retries made a new Stripe customer each time. Keep one, move the cards, remove the empties.
soonOrphaned customers and cards
Stripe holds customers with no WooCommerce user. List the orphans and the renewal risks.
soonDuplicate saved cards
A half finished upgrade left the same card twice. Group by fingerprint and detach the copies.
soonSubscription has no saved card
A retry at checkout dropped the token, so renewals fail. Recover the customer and card from Stripe.
ReconcilerNew card not linked to the sub
The buyer changed cards but the sub still points at the old one. Repoint it to the current card.
ReconcilerPayment method detached
The token is no longer attached to the customer, so renewals are rejected. Reattach or flag it.
soonCard not saved for future renewals
After a manual 3D Secure renewal the card is not set for off session use. The next renewal fails too.
soonSubscription lifecycle
7 guidesOn hold after a good renewal
Stripe took the renewal but the subscription stayed on hold under HPOS. Set it back to active.
ReconcilerSEPA renewal stays active on fail
A slow SEPA debit failed but the sub still shows paid. Set the order failed so retries can start.
soonStaging site pauses live subs
A clone with live keys paused real subscriptions. Find the wrong pauses and resume them.
soonRenewal charged, no order made
Stripe billed the renewal but WooCommerce has no order for it. Reconcile invoices to orders.
soonCard change flips sub to pending
Changing to a 3D Secure card left the subscription pending. Reactivate it and save the new card.
soonCard check read as a failed payment
A failed card check downgraded a live subscription. Restore the subs that were wrongly held.
soonCannot change the card twice
A cached SetupIntent blocks the second card change in one session. Detect and clear the block.
soonCancellation sync
2 guidesBilling runs after WooPayments off
Turning off the plugin left Stripe subscriptions billing on their own. Find and cancel the orphans.
soonStripe bills after cancellation
The sub was cancelled in WooCommerce but Stripe keeps charging. Cancel the Stripe side to match.
soonAlternative payment methods
4 guidesSEPA subs flip to manual renewal
A gateway ID change quietly turned off auto renewals for SEPA. Repair the payment method meta.
soonOld SEPA sources rejected
Saved SEPA sources fail on the new API. Move them to a modern payment method or flag them.
soonStripe Link becomes manual
A Link purchase never saved its card to the sub. Pull the card across so renewals run again.
sooniDEAL and Bancontact for renewals
These one time methods need a SEPA mandate to renew. Check for the mandate or flag the sub.
soonSources to PaymentMethods and SCA
5 guidesMove sources to payment methods
Old src tokens cannot be charged off session. Move them to pm tokens so renewals keep working.
soonPromote the default source
The customer default is a source, not a payment method. Set the modern default so renewals succeed.
soonAdd off session mandate to old subs
Pre SCA subs renew with no mandate and European cards decline. Set up the mandate in bulk.
soonAttach the payment method
A token used without a customer cannot be reused. Attach it and set the default for the sub.
soonLegacy to new checkout cards
The new checkout may not show cards saved the old way. Attach them as reusable payment methods.
soonAccount and store migration
7 guidesRecreate subs after account move
A PAN copy keeps customers but drops subscriptions. Rebuild the billing objects on the new account.
soonStale IDs after a gateway switch
A new Stripe account left old customer IDs that fail. Find and clear the stale meta.
soonRemap customers after a store move
A fresh install has no customer mapping. Match Stripe customers to users by email and write it back.
soonImport cards from another processor
A card import made new IDs and a mapping file. Wire the new tokens into WooCommerce.
soonMove WooPayments to Stripe
The meta keys differ and cards may not move. Remap what you can and drive re entry for the rest.
soonRemove test IDs from live
Test customer and card IDs in a live store break every charge. Find and clear them safely.
soonDetect test vs live key mixups
The wrong mode routes real checkouts to test. Confirm the key mode against Stripe itself.
soonBulk subscription operations
4 guidesBulk swap a reissued card range
An issuer reissued a whole card range and renewals fail. Swap the payment method across many subs.
soonBulk cancel and keep in sync
Cancel many subs at once without leaving one side active. Cancel Stripe and WooCommerce together.
soonBulk pause on both systems
Pause at scale so Stripe stops billing and WooCommerce shows on hold. Keep the two lined up.
soonPush a card change to Stripe
The card changed in WooCommerce but Stripe still charges the old one. Point Stripe at the new card.
soonCatalog, metadata, and scheduling
4 guidesSync products to Stripe
Stripe has nothing to bill without matching products and prices. Upsert them and store the IDs.
soonBackfill order ID metadata
Old Stripe objects have no order ID, so nothing ties out. Match them and patch the metadata.
soonCurrency not enabled on Stripe
A currency shown at checkout is not turned on in Stripe, so payment fails. Report the gaps.
soonRenewals never run
Cron or Action Scheduler is stuck, so renewals and retries never fire. Find the stalled jobs.
soonWooCommerce core: stock and inventory
6 plannedOverselling race drives stock negative
Two orders pass the stock check at once and quantity goes below zero.
RepairFailed order reduces stock, never restored
A failed order cut stock that was never added back when cancelled.
soonDouble stock reduction
One order reduced stock twice, leaving inventory permanently short.
soonStale reserved-stock rows oversell
Old reservation rows hold inventory that a second buyer then oversells.
soonVariations stuck On Backorder at zero
A variation shows On Backorder at zero stock with backorders off.
soonOrder edits do not adjust stock
Adding or removing line items on an order never changes the stock.
soonWooCommerce core: products and catalog
13 plannedProduct lookup table out of sync
The product lookup cache drifts from real stock, price, and sales.
soonOn-sale flag shows products not on sale
The lookup table marks products on sale when they are not.
soonPopularity sort uses stale total sales
Edited total_sales never reaches the lookup, so popularity sort is wrong.
soonDeleting a variation does not resync the parent
A removed variation leaves the parent with stale stock and price.
soonOrphaned product variations
Variations whose parent product is gone bloat the database and collide.
soonDuplicate or missing SKUs
Imports and concurrent writes create duplicate or empty SKUs.
soonProducts stranded with no category
Products with no category vanish from archives and menus.
soonBroken featured images
Products point at deleted attachments, so thumbnails break.
soonProduct visibility terms mis-assigned
A migration bug assigned wrong visibility terms, hiding products.
soonOut of stock but still purchasable
Sold-out products stay buyable and visible in the catalog.
soonExpired sale prices never revert
A finished sale keeps charging the sale price after it ends.
soonAttribute and term counts drift
Layered nav shows wrong product counts per term.
soonRatings count drifts from real reviews
Displayed star counts diverge from the approved reviews.
soonWooCommerce core: coupons
4 plannedCoupon usage count undercounts
Concurrent checkouts lose updates, so usage limits are exceeded.
soonCoupon usage counted twice via REST
A REST order increments usage at pending and again at processing.
soonFailed orders inflate and lock coupons
Held orders keep a coupon locked so real customers cannot use it.
soonCoupon expiry uses UTC not site time
Coupons expire early or stay live around the local date boundary.
soonWooCommerce core: customers and linking
3 plannedGuest orders not linked to accounts
A guest order never links to the account with the same email.
soonDuplicate customer accounts at checkout
A username race creates duplicate accounts for one email.
soonCustomer lookup out of sync
The customer lookup table drifts from the real users list.
soonWooCommerce core: tax, totals, and analytics
5 plannedOrder tax off by a cent (frontend vs API)
The REST API returns a tax total one cent off from the frontend.
soonRounding drifts the order total by a cent
Intermediate rounding leaves historical order totals off by a cent.
soonOrder stats wrong after HPOS migration
Analytics show a false revenue spike after enabling HPOS.
soonTrashed orders still counted in stats
A trashed order keeps inflating Analytics revenue and counts.
soonCustomer lifetime value drifts
Per-customer spend and order counts diverge from real orders.
soonWooCommerce core: HPOS and housekeeping
3 plannedLegacy order rows survive after HPOS cleanup
Old shop_order posts linger after cleanup marks itself done.
soonCheckout-draft orders pile up
Draft orders from the block checkout leak into order queries.
soonInvisible auto-draft orders
Add Order drafts accumulate but never show in the orders list.
soonWooCommerce core: database bloat and maintenance
6 plannedExpired transients bloat wp_options
Expired transients are never deleted and slow every query.
soonClear-transients tool leaves residue
The built-in clear tool misses thousands of WooCommerce transients.
soonAutoloaded options bloat
Oversized autoloaded options slow every single request.
soonSession table balloons
Broken session cleanup lets the sessions table grow without bound.
soonOrphaned postmeta rows
Meta rows for deleted posts pile up in the most-queried table.
soonPersistent cart data never cleared
Abandoned persistent-cart usermeta and sessions linger forever.
soonWooCommerce core: scheduling, cron, and email
5 plannedWP-Cron disabled, emails never send
With no real cron, queued emails and actions never fire.
soonAction Scheduler tables balloon
Action Scheduler tables grow to many gigabytes and slow the queue.
soonCompleted actions never purged
Thousands of succeeded actions pile up and are never pruned.
soonAction Scheduler stuck in-progress
A crashed job stays in-progress and blocks the whole queue.
soonREST pagination breaks on large sets
Paging over many orders silently misses or duplicates rows.
soonWooCommerce Subscriptions: schedules and dates
6 plannedNext payment date drifts after a late renewal
Each late renewal pushes the billing day further out.
soonEarly renewal shifts the billing cadence
An early renewal permanently moves the customer's billing day.
soonTimezone-corrupted next payment dates
Off-by-offset dates fire renewals early or twice.
soonActive sub with a past next payment date
A stalled scheduler leaves a due renewal that never runs.
soonSubscription will not end
A missing expiration action bills past the scheduled end date.
soonHPOS schedule divergence
Schedule dates diverge between the post meta and the order tables.
soonWooCommerce Subscriptions: status and renewals
5 plannedStuck in pending-cancel
The end-of-term action never fires, so it never cancels.
soonCannot reactivate a pending-cancel sub
A leftover end date blocks the return to active.
soonZero-cost renewal orphaned by block checkout
A free renewal spawns a draft order linked to no subscription.
soonDuplicate renewal orders in one cycle
Overlapping actions create two renewal orders for one period.
soonRenewal marked paid with no payment
A cache bug completes a renewal that was never actually paid.
soonWooCommerce Subscriptions: manual renewal and dunning
5 plannedSubscriptions revert to manual renewal
A bug flips auto-renew off, so renewals silently stop.
soonFree trials forced to manual renewal
Block-checkout trials save no payment method and cannot auto-charge.
soonDunning stops before its attempts
Failed-payment retries stop scheduling before the configured count.
soonRenewal actions stall, no renewals made
Stuck scheduled actions leave due renewals uncharged.
soonTrial-end action false-positive failure
A benign trial-end action is flagged failed and adds noise.
soonWooCommerce Subscriptions: switches, coupons, and data
8 plannedProration miscalculated on a second switch
Two switches in one cycle compute an impossible proration.
soonRecurring coupon dropped on switch
A switch loses the recurring discount, so it renews at full price.
soonWrong coupon type on renewals
A sign-up-only coupon is used where a recurring one was meant.
soonLimited-payment coupon miscounts
The coupon applies to the wrong number of payments.
soonSubscription price drifts from the product
A later price or name change never reaches existing subscriptions.
soonOrphaned subscriptions with no customer
Live, billing subscriptions point at no valid user.
soonActive-subscriber counts wrong in reports
Report caches miscount active subscriptions, especially on HPOS.
soonBulk subscription export runs out of memory
The built-in exporter fatals on large subscription sets.
soonFighting a WooCommerce or Stripe bug right now?
If you have a bug in WooCommerce, WooCommerce Subscriptions, or the WooCommerce Stripe gateway that you would rather hand off, this is the kind of work I do. Message me and we can work through it together.
Found this useful?
These guides are free and always will be. If one saved you a support ticket or a refund, you can throw a coffee my way. It keeps the notes coming.
Buy me a coffee on Ko-fi