Blog

Automatically Link WooCommerce Orders at Customer Registration

We got an question from Rob in our comments section on our post about adding registration prompts to WooCommerce emails that makes for an interesting tutorial.

To summary Rob’s question:

How would you reconcile a previous order when a guest user registers? In other words: say I buy from your store and use my email (test@test.com) at checkout. I then get this lovely email with a registration prompt, so I go and register. The problem is, I don’t have any orders in My Account. This leaves me confused.

This is a great point that Rob brings up — registration doesn’t immediately pick up on existing orders (based on email) and link them to the customer account.

As a store owner, you can take this action manually under WooCommerce > Reports > Customers > Customer List pretty easily:

WooCommerce: Link past orders

However, this isn’t automated for each customer, but it could be.

Link WooCommerce Orders at Registration

Turns out that linking previous WooCommerce orders upon customer registration is super simple. However, note that I would not recommend this for sites with tens of thousands of order records (or as many blog posts / other kinds of posts), so at some point, you’d likely need to remove this if you implement our snippet to automatically link orders.

The reason is that WooCommerce has to do a query for order meta to check for orders that have the billing email being used to register an account. Meta queries can be slow when checking over thousands of posts, so this can make your registration process very slow (a big problem if it’s happening during checkout), potentially even timing out if you have enough orders.

For many stores with a smaller order volume this implementation could work, and eventually when WooCommerce migrates to a custom data structure (probably in v3.0) this query could likely be optimized a lot by then, but this is your fair warning at present that it could slow large sites down at checkout / registration.

So let’s get back to linking those orders — why is this simple? Turns out registration automatically gives us the one piece of information we need to do it.

The registration hook gives us the user ID, and that’s all that’s required to link previous WooCommerce orders to this user via the wc_update_new_customer_past_orders() function, so we can run one function at registration:

/**
 * Links previous orders to a new customer upon registration.
 *
 * @param int $user_id the ID for the new user
 */
function sv_link_orders_at_registration( $user_id ) {
    wc_update_new_customer_past_orders( $user_id );
}
add_action( 'woocommerce_created_customer', 'sv_link_orders_at_registration' );

(Note that we’re only hooking into registrations processed by WooCommerce, not all registrations for the site.)

That’s all it takes! When a new user is logged in, now the orders that were placed with this billing email in the past will be linked, and viewable from the account area.

WooCommerce: Previous Orders Linked

Now that’s certainly workable, but not quite SkyVerge Overengineered™ yet.

Let’s make this process a bit more seamless to show a welcome message to our newly registered user, telling him or her exactly how many previous orders have been linked.

Display WooCommerce Linked Orders Count

While the wc_update_new_customer_past_orders() function will link orders as desired, it will also return the count for the number of orders it updated. We can stash this count as part of the user’s details to inform them of it when they log it.

(We have to use user meta because we’re hooked in too early here to stash the info in the session — it will be overridden after this point when logging the new user in.)

/**
 * Links previous orders to a new customer upon registration.
 *
 * @param int $user_id the ID for the new user
 */
function sv_link_orders_at_registration( $user_id ) {
    $count = wc_update_new_customer_past_orders( $user_id );
    update_user_meta( $user_id, '_wc_linked_order_count', $count );
}
add_action( 'woocommerce_created_customer', 'sv_link_orders_at_registration' );

Alright, now we’ve got a flag for our user that tells us how many orders are linked! Let’s check that flag on the account page, and if we have it (and it’s greater than 0), lets inform the user the first time they visit the dashboard. We’ll then delete the flag so we don’t constantly show this notice.

/**
 * Shows the "orders linked" notice upon first account visit if any were linked at registration.
 *
 * USES WOOCOMMERCE 2.6+ -- update the action name for older versions
 */
function maybe_show_linked_order_count() {

    $user_id = get_current_user_id();

    if ( ! $user_id ) {
        return;
    }

    // check if we've linked orders for this user at registration
    $count = get_user_meta( $user_id, '_wc_linked_order_count', true );

    if ( $count && $count > 0 ) {
    
        $name = get_user_by( 'id', $user_id )->display_name;

        $message  = $name ? sprintf( __( 'Welcome, %s!', 'text' ), $name ) : __( 'Welcome!', 'text' );
        $message .= ' ' . sprintf( _n( 'Your previous order has been linked to this account.', 'Your previous %s orders have been linked to this account.', $count, 'text' ), $count );
        $message .= ' <a class="button" href="' . esc_url( wc_get_endpoint_url( 'orders' ) ) . '">' . esc_html__( 'View Orders', 'text' ) . '</a>';

        // add a notice with our message and delete our linked order flag
        wc_print_notice( $message, 'notice' );
        delete_user_meta( $user_id, '_wc_linked_order_count' );
    }
}
add_action( 'woocommerce_account_dashboard', 'maybe_show_linked_order_count', 1 );

Now let’s take a look at what this does. When registering from the account page, we likely don’t have a first or last name to show, so the username / current display name will welcome the customer and show them the order count that has been linked, along with a call to action to view past orders.

WooCommerce Previous Orders linked at Registration

Registered from account

From checkout, we’ll likely have more details, so a first name is probably available, making your message even more personal:

WooCommerce Previous Orders linked at checkout

Registered from checkout

Once the message has been shown, the flag is deleted, so it won’t be shown again to the user.

That’s a wrap! If you want this in plugin form, you can view the source code here and download a zip file to install.

Remember, this isn’t recommended for sites with tens of thousands of orders, so it’s “use at your own risk”. I’d recommend testing on a staging site before implementing in a live environment so you can do some benchmarking before implementing. Hope this helps, Rob!

3 Comments

  • […] has a tutorial on automatically linking past orders to WooCommerce customers when they register on your […]

  • Doug Smith 3 weeks ago Reply

    I had always wondered why this was not done automatically. It makes perfect sense now after reading your explanation of how it works.

    I did a little digging and found that the Customer List report actually does a similar search for previous orders just to decide if the button to link previous orders should be shown or not. It only returns the first order it can find with a matching e-mail address, but it’s still pretty intensive. The report won’t even finish loading the page on a site I have with a lot of orders—and now I understand why.

    • Beka Rice 2 weeks ago Reply

      Yep, that makes sense! As you can see this query is already being abstracted to use the new wc_get_orders() method, so hopefully when the underlying structure changes it can be much faster.

Submit a Comment