Skip to content
SaniyajMallik
← All work

Migration · E-commerce2026

Subscription store migration for a nonprofit publisher

A literary nonprofit split one old WordPress site into two — one for the organisation, one for its publishing press. I moved the press's subscription store — 3,430 customers, their full order history, 547 subscriptions, gift subscriptions and memberships — without losing a record or charging anyone by mistake.

Focus
WooCommerce Subscriptions, Memberships, Data migration, Custom plugin
Outcome
547 subscriptions and 3,430 customers moved with their full history
Business
Kept private
https://.com
Subscription store migration for a nonprofit publisher

The nonprofit and its press had shared one website for years. As they moved to separate sites, the press's book membership — every new title delivered to subscribers, billed monthly or yearly, often bought as a gift — had to move with it. Customers, renewals, gift recipients and member perks were all tied together by IDs that would change in the move, and any slip meant subscribers charged twice, cut off, or keeping access they'd cancelled.

  1. 01Moved 3,430 users and the full order history with WP All Import, keeping a legacy-to-new ID map for every user and order so each renewal stayed linked to its original order.
  2. 02Built a custom Batch Subscription Updater plugin: upload a CSV, preview the changes in a dry run, then set statuses and link parent and renewal orders — in batches small enough for the host's 59-second limit.
  3. 03Wrote Python scripts to check every membership against its subscription. They found 210 mismatches — including 146 cancelled subscribers who still had access — and produced a targeted fix file.
  4. 04Mapped 52 gift subscriptions from purchaser to recipient, and found and imported the recipients who didn't yet have accounts on the new site.
  5. 05Reactivated exactly the 47 subscriptions whose renewals fell inside the migration pause, with a verified list sent to the client before any bulk change.
  6. 06Tracked down a subtle PHP bug — ltrim() treats its second argument as a set of characters, not a prefix, so 'cancelled' became 'ancelled' — and worked around it without risking the live data.

All 547 subscriptions and their history arrived on the new site with every status checked, memberships matching what people actually pay for, and gift recipients linked to their subscriptions — with no disruption for active subscribers.