I have a client that sells digital products and whose setup was composed of:
- An old Inventory Software system that handled download permissions.
- A custom Wordpress installation that provided customer access.
- A custom Wordpress shopping cart.
All of this software was built around 10 years ago, was poorly documented and kept failing - a true nightmare. After a discussion with my client, we decided to merge all of these systems into a single one, powered by Wordpress and WooCoomerce. His team was already familiar with Wordpress, so the move to WooCommerce was a good technical and business choice - no one would need extra training, and the implementation effort would not be high because we’d leverage existing tools.
The migration was a success - the new system is faster and very reliable, and the client is having great results with it (read: more sales $$$). The overall process was pretty straightforward, but I had a hard time automating the customers migration from the old platform to the new platform. In this case, I needed to:
- Notify each customer about his new account.
- Send the customer a new receipt, with new download instructions.
- Preserve the order dates to not screw with the order statistics.
After lots of research and testing, I came up with the script below. Basically, it imports a list of orders from a CSV file, and then creates, as necessary, new users and orders on WooCommerce. I’ve included a few explanatory comments on the body of the script.
<?php
if (php_sapi_name() !== 'cli') {
die("This script is meant to be run from the command line");
}
set_time_limit(0);
ini_set('max_execution_time', 0);
function find_wordpress_base_path() {
$dir = dirname(__FILE__);
do {
if( file_exists($dir."/wp-config.php") ) {
return $dir;
}
} while($dir = realpath("$dir/.."));
return null;
}
define('BASE_PATH', find_wordpress_base_path()."/");
define('WP_USE_THEMES', false);
global $wp, $wp_query, $wp_the_query, $wp_rewrite, $wp_did_header;
require(BASE_PATH . 'wp-load.php');
/**
* Helper function: it maps the original product ID to the new product ID.
* @param string $originId
* @return int
*/
function getProductId($originId) {
$ids = [
23 => 2141
, 24 => 2142
, 25 => 2143
, 26 => 2145
, 27 => 2146
, 28 => 2147
, 29 => 2148
];
if (array_key_exists($originId, $ids)) {
return $ids[$originId];
}
return false;
}
if (!isset($argv[1]) || !file_exists($argv[1])) {
echo "The input file was not specified or it does not exist.\n";
exit;
}
// Read the file informed via STDIN.
$csv = fopen($argv[1], 'r');
$data = [];
while (($row = fgetcsv($csv)) !== false) {
// Extract the parameters from the current row.
list(
$email
, $firstName
, $lastName
, $phone
, $address
, $city
, $state
, $zipcode
, $country
, $createdAt
, $products) = $row;
$products = array_filter(array_unique(explode(',', $products)));
// Check if we have a valid number of products; if not, we skip this row.
if (count($products) == 0) {
continue;
}
// Check if the user already exists.
$userId = email_exists($email);
// Create a new user and notify him.
if (!$userId && !username_exists($email)) {
$password = wp_generate_password(8, false);
$userId = wc_create_new_customer($email, '', $password);
}
// If we can't find/create an user, it logs an error.
if (is_wp_error($userId)) {
error_log("Failed creating user {$email}.");
continue;
}
// Prepare the customer address for the order.
$customerAddress = [
'first_name' => $firstName
, 'last_name' => $lastName
, 'company' => ''
, 'email' => $email
, 'phone' => $phone
, 'address_1' => $address
, 'address_2' => ''
, 'city' => $city
, 'state' => $state
, 'postcode' => $zipcode
, 'country' => $country
];
// Create a new order, and set the billing and shipping addresses.
$order = wc_create_order(['customer_id' => $userId]);
$order->set_address($customerAddress, 'billing');
$order->set_address($customerAddress, 'shipping');
foreach ($products as $originId) {
$productId = getProductId($originId);
if ($productId) {
// Fetch the product from the database.
$product = new WC_Product($productId);
if ($product) {
// Add the product to the order.
// In this case, we only add a single unit of each product.
$order->add_product($product, 1);
}
}
}
// Persist the order.
$order->calculate_totals();
// Confirm the order payment and add a note to it.
$order->add_order_note('Order automatically imported from legacy system.');
$order->payment_complete();
// Update the order date to the original order date.
// This is useful to not screw with the order statistics.
wp_update_post([
'ID' => $order->id
, 'post_date' => $createdAt
, 'post_date_gmt' => $createdAt
, 'post_modified' => $createdAt
, 'post_modified_gmt' => $createdAt
], true);
}
To run it, you must upload it to the Wordpress root directory, SSH into the server and call it with the required arguments:
php import.php users_dump.csv