Created
January 26, 2026 21:49
-
-
Save dhilowitz/8b4ff657bfc166771950c72de588d050 to your computer and use it in GitHub Desktop.
WordPress/WooCommerce CLI script to associate guest orders with user accounts. Automatically creates users if they don't exist and links all past orders by billing email.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env php | |
| <?php | |
| /** | |
| * Associate Guest Orders with User Accounts | |
| * | |
| * This script goes through all WooCommerce orders and: | |
| * 1. Finds orders with guest customers (no user ID) | |
| * 2. Checks if a user exists with the billing email | |
| * 3. Creates a new user if one doesn't exist | |
| * 4. Associates the order with the user account | |
| * | |
| * Put this script in the root of your Wordpress installation and run it from the command-line. | |
| * This script comes with no WARRANTY. USE AT YOUR OWN RISK. ALWAYS BACK UP YOUR DATA FIRST. | |
| * | |
| * Usage: php associate-guest-orders.php [--dry-run] | |
| */ | |
| // Check if running from command line | |
| if (php_sapi_name() !== 'cli') { | |
| die("This script can only be run from the command line.\n"); | |
| } | |
| // Parse command line arguments | |
| $dry_run = in_array('--dry-run', $argv); | |
| // Determine the WordPress root directory | |
| $wp_root = dirname(__FILE__); | |
| if (!file_exists($wp_root . '/wp-load.php')) { | |
| die("Error: Cannot find wp-load.php. Please run this script from the WordPress root directory.\n"); | |
| } | |
| // Load WordPress | |
| require_once($wp_root . '/wp-load.php'); | |
| // Check if WooCommerce is active | |
| if (!class_exists('WooCommerce')) { | |
| die("Error: WooCommerce is not active.\n"); | |
| } | |
| // Initialize counters | |
| $total_orders = 0; | |
| $guest_orders = 0; | |
| $orders_associated = 0; | |
| $users_created = 0; | |
| $errors = 0; | |
| echo "================================================================================\n"; | |
| echo "Associate Guest Orders with User Accounts\n"; | |
| echo "================================================================================\n"; | |
| if ($dry_run) { | |
| echo "MODE: DRY RUN (no changes will be made)\n"; | |
| echo "================================================================================\n"; | |
| } | |
| echo "\n"; | |
| // Process orders in batches to avoid memory issues | |
| $batch_size = 500; | |
| $offset = 0; | |
| $has_more = true; | |
| echo "Processing orders in batches of {$batch_size}...\n\n"; | |
| while ($has_more) { | |
| // Get batch of orders | |
| $args = array( | |
| 'limit' => $batch_size, | |
| 'offset' => $offset, | |
| 'orderby' => 'date', | |
| 'order' => 'ASC', | |
| 'return' => 'ids', | |
| 'type' => 'shop_order', | |
| ); | |
| $order_ids = wc_get_orders($args); | |
| if (empty($order_ids)) { | |
| $has_more = false; | |
| break; | |
| } | |
| echo "Processing batch: orders " . ($offset + 1) . " to " . ($offset + count($order_ids)) . "\n"; | |
| // Process each order | |
| foreach ($order_ids as $order_id) { | |
| $total_orders++; | |
| try { | |
| $order = wc_get_order($order_id); | |
| if (!$order) { | |
| echo "⚠️ Order #{$order_id}: Could not load order\n"; | |
| $errors++; | |
| continue; | |
| } | |
| // Get order details | |
| $order_user_id = $order->get_user_id(); | |
| $billing_email = $order->get_billing_email(); | |
| // Skip if order already has a user associated | |
| if ($order_user_id > 0) { | |
| continue; | |
| } | |
| $guest_orders++; | |
| // Skip if no billing email | |
| if (empty($billing_email)) { | |
| echo "⚠️ Order #{$order_id}: No billing email found\n"; | |
| $errors++; | |
| continue; | |
| } | |
| // Check if user exists with this email | |
| $user = get_user_by('email', $billing_email); | |
| if (!$user) { | |
| // Create new user | |
| $billing_first_name = $order->get_billing_first_name(); | |
| $billing_last_name = $order->get_billing_last_name(); | |
| // Generate username from email or first name | |
| $username = !empty($billing_first_name) ? sanitize_user($billing_first_name) : sanitize_user(current(explode('@', $billing_email))); | |
| // Ensure unique username | |
| $base_username = $username; | |
| $counter = 1; | |
| while (username_exists($username)) { | |
| $username = $base_username . $counter; | |
| $counter++; | |
| } | |
| if ($dry_run) { | |
| echo "🔍 Order #{$order_id}: Would create user '{$username}' for {$billing_email}\n"; | |
| $users_created++; | |
| } else { | |
| // Generate random password | |
| $random_password = wp_generate_password(12, true, true); | |
| // Create the user | |
| $user_id = wp_create_user($username, $random_password, $billing_email); | |
| if (is_wp_error($user_id)) { | |
| echo "❌ Order #{$order_id}: Failed to create user for {$billing_email} - " . $user_id->get_error_message() . "\n"; | |
| $errors++; | |
| continue; | |
| } | |
| echo "✅ Order #{$order_id}: Created user '{$username}' (ID: {$user_id}) for {$billing_email}\n"; | |
| $users_created++; | |
| // Mark as guest customer | |
| update_user_meta($user_id, 'guest', 'yes'); | |
| // Update user's billing data | |
| update_user_meta($user_id, 'billing_first_name', $order->get_billing_first_name()); | |
| update_user_meta($user_id, 'billing_last_name', $order->get_billing_last_name()); | |
| update_user_meta($user_id, 'billing_company', $order->get_billing_company()); | |
| update_user_meta($user_id, 'billing_address_1', $order->get_billing_address_1()); | |
| update_user_meta($user_id, 'billing_address_2', $order->get_billing_address_2()); | |
| update_user_meta($user_id, 'billing_city', $order->get_billing_city()); | |
| update_user_meta($user_id, 'billing_state', $order->get_billing_state()); | |
| update_user_meta($user_id, 'billing_postcode', $order->get_billing_postcode()); | |
| update_user_meta($user_id, 'billing_country', $order->get_billing_country()); | |
| update_user_meta($user_id, 'billing_email', $billing_email); | |
| update_user_meta($user_id, 'billing_phone', $order->get_billing_phone()); | |
| // Update user's shipping data | |
| update_user_meta($user_id, 'shipping_first_name', $order->get_shipping_first_name()); | |
| update_user_meta($user_id, 'shipping_last_name', $order->get_shipping_last_name()); | |
| update_user_meta($user_id, 'shipping_company', $order->get_shipping_company()); | |
| update_user_meta($user_id, 'shipping_address_1', $order->get_shipping_address_1()); | |
| update_user_meta($user_id, 'shipping_address_2', $order->get_shipping_address_2()); | |
| update_user_meta($user_id, 'shipping_city', $order->get_shipping_city()); | |
| update_user_meta($user_id, 'shipping_state', $order->get_shipping_state()); | |
| update_user_meta($user_id, 'shipping_postcode', $order->get_shipping_postcode()); | |
| update_user_meta($user_id, 'shipping_country', $order->get_shipping_country()); | |
| // Update first and last name | |
| wp_update_user(array( | |
| 'ID' => $user_id, | |
| 'first_name' => $billing_first_name, | |
| 'last_name' => $billing_last_name, | |
| )); | |
| // Associate the order with the new user | |
| $order->set_customer_id($user_id); | |
| $order->save(); | |
| $orders_associated++; | |
| } | |
| } else { | |
| // User exists - associate order | |
| $user_id = $user->ID; | |
| if ($dry_run) { | |
| echo "🔍 Order #{$order_id}: Would associate with existing user '{$user->user_login}' (ID: {$user_id}) - {$billing_email}\n"; | |
| } else { | |
| $order->set_customer_id($user_id); | |
| $order->save(); | |
| echo "✅ Order #{$order_id}: Associated with user '{$user->user_login}' (ID: {$user_id}) - {$billing_email}\n"; | |
| } | |
| $orders_associated++; | |
| } | |
| } catch (Exception $e) { | |
| echo "❌ Order #{$order_id}: Exception - " . $e->getMessage() . "\n"; | |
| $errors++; | |
| } | |
| } | |
| // Move to next batch | |
| $offset += $batch_size; | |
| // Clear object cache to free memory | |
| wp_cache_flush(); | |
| if (count($order_ids) < $batch_size) { | |
| $has_more = false; | |
| } | |
| } | |
| // Print summary | |
| echo "\n"; | |
| echo "================================================================================\n"; | |
| echo "Summary\n"; | |
| echo "================================================================================\n"; | |
| echo "Total orders processed: {$total_orders}\n"; | |
| echo "Guest orders found: {$guest_orders}\n"; | |
| echo "Orders associated: {$orders_associated}\n"; | |
| echo "New users created: {$users_created}\n"; | |
| echo "Errors: {$errors}\n"; | |
| echo "================================================================================\n"; | |
| if ($dry_run) { | |
| echo "\nThis was a DRY RUN. No changes were made.\n"; | |
| echo "Run without --dry-run to actually process the orders.\n"; | |
| } | |
| echo "\nDone!\n"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment