WooCommerce Link Guest Orders to Customer Accounts(Existing & New Orders)

Faizan Shaikh, May 9, 2023

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.

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.

Oh hi there 👋 It’s nice to meet you.

Sign up to receive awesome WordPress content in your inbox

We don’t spam! Unsubscribe anytime.

6 comments

  • Unity Garcia

    Amazing! Thanks

  • I get the error:
    Fatal error: Uncaught Error: Call to undefined method Automattic\WooCommerce\Admin\Overrides\OrderRefund::get_billing_email()

    I think its an issue with.
    $order = wc_get_order($order_id);
    getting refunded orders. but I dont know how to correct it !

  • nevermind apparently this comment section wont allow the full code.

  • here is a little bit better snippet with some on screen info about the process and success.

    “ids”, // Just the ids
    “posts_per_page” => 10, // Number of orders to retrieve per request
    “paged” => $page, // Pagination
    ];

    $order_ids = wc_get_orders($args);
    $total_orders = count($order_ids);
    if ($total_orders == 0) {
    // No more orders to process
    break;
    }

    echo “Processing page {$page} with {$total_orders} orders”;

    foreach ($order_ids as $order_id) {
    // Get the order
    $order = wc_get_order($order_id);

    // Check if the order is a regular order and not a refund
    if ($order && is_a($order, ‘WC_Order’)) {
    // 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();
    echo “Linked order {$order_id} to user {$user->ID}”;
    } else {
    echo “No user found with email {$order_email} for order {$order_id}”;
    }
    } else {
    echo “Order {$order_id} already linked to a user”;
    }
    } else {
    echo “Order {$order_id} is a refund or invalid order”;
    }

    $processed_orders++;
    echo “Total processed orders: {$processed_orders}”;
    flush(); // Flush the output buffer to see progress in real-time
    }

    $page++; // Increment the page number for the next batch of orders
    }

    echo “Processing completed.”;
    ?>

  • Hi,

    I have added the php to link guest orders by emails to my server about 3hrs ago, but nothing happens.
    Is this still functional?
    Orders remain being unlinked. I have about 1000 orders to be linked, do I need to wait longer? How will I know the php has done the job?
    Would love your help.
    Thanks,
    Celine

  • link new guest orders to existing users (by email) use this snippet:

    //assign user in guest order
    add_action( ‘woocommerce_new_order’, ‘action_woocommerce_new_order’, 10, 1 );
    function action_woocommerce_new_order( $order_id ) {
    $order = new WC_Order($order_id);
    $user = $order->get_user();
    if( !$user ){
    //guest order
    $userdata = get_user_by( ’email’, $order->get_billing_email() );

    if(isset( $userdata->ID )){
    //registered
    update_post_meta($order_id, ‘_customer_user’, $userdata->ID );
    }else{
    //Guest
    }
    }
    }

Leave your comment