Within the business climate of the current pandemic, many businesses are attempting to shift more and more online. One of the favorite models of this for online sales is to get recurring income via online memberships that grant customers access to exclusive video content, whether that’s pre-recorded or on-demand. While a great business model, until one reaches a critical number of subscribers, the effort and cost to continue to product valuable content is challenging. This was the situation facing two of my clients Primal Vinyasa Online (Site A), and the Yoga Union (Site B). Combining forces and technologies grants many obvious benefits. The savings on annual plugin licenses and web hosting alone is about $700 . However, the technological challenges of how to pull this off with only minimal disruption to the customer is quite difficult.
I discovered that there wasn’t any comprehensive tutorials on how to pull this off, so this is my attempt to document the process that I went through. Thankfully both these sites were built on the same technology stack:
- WooCommerce Memberships
- WooCommerce Subscriptions
- WPBakery Page Builder
- Custom built child themes of The7, a premium WP theme I use frequently.
- Stripe as billing method
The desired end result is to have 1 merged website that has all the content, customers, subscription products, ongoing automatic subscriptions, and membership content restrictions that were previously spread across two different websites using two different payment accounts. Site A Subscription grants access to it’s traditional offerings, plus some additional on-demand classes. Site B Subscription grants access to it’s own traditional offerings, plus some additional on-demand classes in cross over categories. An additional challenge is that we wanted to be able to provide an option for customers to be able to upgrade their current subscriptions to get an all-access membership that grants access to everything.
One of the main objectives is to make sure that the imported subscriptions are renewed via Stripe, rather than being imported under the status of “Manual renewal”
In summary, we needed to accomplish these things to pull this off:
- Copy over all restricted access content from Site B to Site A
- Copy over all customer user accounts, and passwords from Site B to Site A
- Make customer’s previous simple subscriptions into variable subscription products so that customers can upgrade for greater access.
- Migrate all subscription orders
- Migrate all ongoing subscriptions so payments continue as before
- Merge customer data from 2 seperate Stripe accounts into one
- Migrate WooCommerce memberships (tied to subscriptions) from Site B to Site A
- Notify customers that this has happened.
For effort reference, this took me about 15 hours to pull off, and couldn’t have been done without some very useful external resources and WordPress plugins. I know it’s possible to probably have done this without these, but I don’t have the deep MySQL knowledge to do that.
- Stripe Customer service
- Order, Coupon, Subscription Import Export by WebToffee
- WP All Export Pro by Soflyy
- WP All Export User Export Add-On Pro by Soflyy
- WP All Import Pro by Soflyy
- User Switching
2) Merging in customer user accounts
We’re using the WP All Import plugin because it can import customer’s passwords along to the new site, something which other tools I’ve explored don’t do. Export the specific post type of “WooCommerce Customers“. Export a CSV file. Really, the most important fields are:
- User email
- user login
- first name
- last name
- user registered
- user pass
Using the WP All Export plugin, you’ll want to use the customize export box because otherwise the hashed passwords won’t get transferred along.
I’ve found that using just the normal “Migrate Customers” button works just fine.
You’ll create an export template by selecting which fields you want to export. On the import side, you’ve got an import interface that requests that you match the exported column fields into the user account info areas.
Click on the header values in the right hand side, and drag them over to the respective matching fields on the left.
Or to save you some time, I’ve created a template file you can import via the settings page, located at yoursite.com/wp-admin/admin.php?page=pmxi-admin-settings
On step 4, For the unique identifier, go ahead and click the “auto-detect” button. Unless you have good reason otherwise check the checkboxes for: Create new customers from records newly present in your file, Update existing customers with changed data in your file. Because we want to customize the notification to users about this migration, I’m also enabling the option of ” Block email notifications during import”
You may need to do a customer accounts import again if there are new customer time between the last import and when you are supposed to go live
3. Migrate all subscription orders
Use Webtoffee’s plugin and export all the orders for your subscription product from Site A. In the CSV that’s created, go into line_item_1 and find the product_id. You’ll likely want to do a “find and replace all” on this. In Site B, go into the order import tool. Make sure to select the option for link orders via SKU instead of product ID.
AGAIN: Before importing the orders, please make sure you have imported all the users belonging to the orders you are importing. The customer_email field will be used to associate the orders with the users. If a customer_email of an order matches with the user in the site, the imported orders will be associated with those users by default. If the user is not available and the “Create user option” is enabled under the settings in the previous screen, this plugin will create a new user with the customer_email. If this option is not enabled these orders will be created as guest orders.
If your Site A has had a couple hundred subscriptions, and been running for many months, the # of orders is likely to number in the thousands. This import is thus likely to take a fair bit of time. Some webhosts like WP Engine proactively kill off any long running processes like this (for the sake of stability and performance), so make sure to ask them disable this temporarily for your account.
I recommend not doing anything else with Site B while this occurs, in order to potentially triggering an import failure.
I recommend doing this at a time in which there are no upcoming subscription renewals occuring in the next couple of hours while you’re doing this. For customers who have upcoming payments occurring, make note of who those people are. Pause their subscriptions on Site A, then after migration of everything, go into Site B and manually change the date of their next renewal to later in that day.
At the end of the import, make note of any orders that had the status of “Order with same ID already exists”
4. Migrate your memberships
WooCommerce memberships has a native interface that you can use to work with. When exporting the members, choose the Subscription plan you’re attempting to migrate. For my migration, I excluded memberships with the status of cancelled or expired, in order to reduce the amount of entries in the database I’d have to sort through later on in the site. A smaller DB is a faster DB, and a faster WP backend. If someone who who previously had a canceled subscription/membership wants to re-activate it, there’s generally nothing stopping them from just signing up again, under a brand new subscription.
I like to select the option for “Create a new user if no matching user is found (skips rows when disabled)” since it gives me the option do double check my work for importing users.
Create a new user if no matching user is found (skips rows when disabled)
In the CSV file, use search and replace to change out the membership_plan_id, membership_plan, and membership_plan_slug if necessary
5. Switch Stripe Accounts
It is critical to do this before you migrate the subscriptions. Otherwise the payment method will show up as manual versus via Stripe (automatic).
You’ll want to make sure that Stripe has all your customers info copied over. If there is a delta between the time this takes, you may want to make note of who those customers are and look them up in the final stripe account.
Make sure that your designated Stripe account has a webhook created for the new website you’re using, Site B. Webhooks are used to notify your server about events that happen in your Stripe account, such as a payout completing or an invoice being created. This can be found at https://dashboard.stripe.com/account/webhooks. You’ll want to make sure that you’re also updating the webhook signing secret. I’ve found better results with using just the minimal events.
If you don’t update the webhook signing secret key, then payments often still go through, but you’ll get a bunch of notices from Stripe that they’re having “trouble sending requests to a webhook endpoint”.
6. Migrate your subscriptions
In order to free up server memory, I recommend deactivating all non-essential plugins nduring this process.
Using the webtoffee plugin, export the subscriptions with the status of “pending, active, on hold, and pending cancellation”. As before, I changed the product ID, even though there is an option for “Link products using SKU instead of Product ID”. Also enable the option for “Link related orders using _wt_import_key”
Ensure that all subscriptions that were designated as pending-cancelation properly have that status upon import.
For me the first time, some of the subscriptions that should have been imported under the payment method of Stripe ended up being imported as Manual Renewal. Looking at the site A details of these customers, I realized that frequently they had multiple subscriptions, some of which were as manual renwal and some that were set up properly. On Site A, I went through and deleted the redundant subscriptions. I then deleted ALL the subscriptions on Site B and re-imported these individually and the subscriptions worked.
TOOLS & TRICKS
The WooCommerce Scheduled Actions page is going to be really useful for testing, since with it you can force scheduled renewals to occur much faster. This is located at https://YOURWEBSITE.com/wp-admin/tools.php?page=action-scheduler. Read details about this tool at the Complete Guide to Scheduled Events with Subscriptions
To test your subscription renewal, find the subscription ID, then type it into the search field. Sort the results by the Scheduled Date, and the most upcoming one should come up. You can then force this test subscription to renew immediately. Otherwise, the soonest WC will let you bump up the renewal date/time is at least 1 hour into the future.
Oddly, I’ve found on some websites this is reachable via an option under Tools. But on other websites this doesn’t show up at all.