WooCommerce does not automatically link past guest orders to new user accounts. That should have been the default behavior, but unfortunately that’s not the case.
Anyways, here’s the solution
<?php
require_once $_SERVER["DOCUMENT_ROOT"] . "/wp-load.php";
// Get all orders with 'guest' status
$args = [
"status" => "completed", // Completed orders
"return" => "ids", // Just the ids
];
$order_ids = wc_get_orders($args);
foreach ($order_ids as $order_id) {
// Get the order
$order = wc_get_order($order_id);
// Check if the order was made by a guest
if (0 == $order->get_user_id()) {
// This order was made by a guest
// Now we get the order's billing email
$order_email = $order->get_billing_email();
// Search for a user with this email
$user = get_user_by("email", $order_email);
if ($user) {
// We found a user with this email
// Now we link the order to this user
$order->set_customer_id($user->ID);
$order->save();
}
}
}
Put this code in a .php
file and upload the file to the root of your server. Example, if you used quvor.php
then go to yourwebsite.com/quvor.php
Executing this script can take a good amount of time, depending on the number of orders you have, and your server speed. You may need to increase your max_execution_time
in PHP settings.
If it times out, you can refresh the page again. Make sure to back up your website before running the script.
If you want to link guest orders by emails(which is what I needed), you can use the below script
<?php
require_once $_SERVER["DOCUMENT_ROOT"] . "/wp-load.php";
$emails = ["[email protected]", "[email protected]"]; // put the emails here
// Loop through each email
foreach ($emails as $email) {
// Use WP_Query to get all guest orders for the current email
$args = [
"post_type" => "shop_order",
"post_status" => "any",
"meta_query" => [
[
"key" => "_billing_email",
"value" => $email,
"compare" => "=",
],
[
"key" => "_customer_user",
"value" => 0,
"compare" => "=",
],
],
];
$orders = get_posts($args);
// If there are any orders
if ($orders) {
// Get the WP_User object for the current email
$user = get_user_by("email", $email);
// If a user exists for the email
if ($user) {
// Loop through each order
foreach ($orders as $order) {
// Update the _customer_user meta field with the user's ID
update_post_meta($order->ID, "_customer_user", $user->ID);
}
}
}
}
That’s it. Once the script is successfully executed, all your store orders will be linked to users who have an account.
Once that’s done, make sure to delete the file.
Link Newly Created Customer with Past Guest Orders
The previous script won’t do anything for future orders.
Somethings the guest users when placing a new order decide to register. In this case, their previous orders are not linked to their new accounts.
To fix that, add the below code to your child theme’s functions.php
or a code snippets plugin.
<?php
/* Credits: https://stackoverflow.com/questions/71112271/how-to-link-woocommerce-guest-orders-to-customer-account-after-registration */
function action_woocommerce_created_customer( $customer_id, $new_customer_data, $password_generated ) {
// Link past orders to this newly created customer
wc_update_new_customer_past_orders( $customer_id );
}
add_action( 'woocommerce_created_customer', 'action_woocommerce_created_customer', 10, 3 );
That is it. You don’t need to remove this snippet.