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:
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.
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.
From checkout, we’ll likely have more details, so a first name is probably available, making your message even more personal:
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!
Need some help taking this code further? We recommend Codeable for small custom projects.
[…] has a tutorial on automatically linking past orders to WooCommerce customers when they register on your […]
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.
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.Hi, what is, in your opinion, best setup for WC shop owners,
when they just starting fresh on-line store?
To force only registered users to register before buying product,
and in long termprevent this time-consuming wc queries on register.
Or allow unregistered users to buy, and when a blog/shop gets large
in any post types number remove this snippet?
Will WC authors consider to add this functions as default?
Sorry for my poor English.
Hey Gabrielle, we recommend allowing guest checkout, as there’s a fair bit of research that indicates allowing guest checkout improves conversions. I’d likely recommend this approach: “Or allow unregistered users to buy, and when a blog/shop gets large in any post types number remove this snippet?” Hopefully, for a new store, by the time your store gets large enough that this snippet would cause issues, WooCommerce will have already moved orders to a new data type (not posts), so one could avoid the issues I’ve outlined here 🙂
Has this happened yet: “when WooCommerce migrates to a custom data structure (probably in v3.0) this query could likely be optimized a lot by then”?
If WooCommerce has migrated to a custom data structure does your code need to be updated and if so how?
WooCommerce hasn’t done so yet — the current v3.0 was originally v2.7. So 3.0 added the helpers to make a custom data structure possible, but this isn’t coming until v4.0.
Ok, thank you!
Thank you Beka!
I’ve used a lot of your snippet and tutorials and it’s the time to show you some love 😀
when I search for a little complicated WooCommerce problem, I usually find the solution here. super super helpful.
Also, your plugins rocks! my clients are the ones who purchase it so I didn’t have a chance to post a review on them myself. but will definitely do when I run my own e-commerce site.
Thanks again, have a nice day.
<3 thanks for the kind words, Ahmed! So glad to hear our blog + plugins have been helpful 🙂
Thanks Beka, could you tell me how can we send an automatic reset password email to the new users?!
Hi Beka,
This is a great solution. But is this updated for the latest Woocommerce? I’ve tried installing the plugin but it didn’t work. Hope to hear from you!
Hey Leon, it still works with the latest version, so I’d switch to a default theme like Storefront + deactivating other plugins, as this is likely a theme or plugin conflict on your site.
Hi Beka,
is there a script i can use to bulk link all previous orders for all my guests orders?
I love the reports section but I wish it had a little more control. Like if the columns were sortable, especially by Money Spent.
Also if there was a customer view that showed each customer’s spend on the store in a given time frame, but a view that showed all customers. Basically the Custom time frame feature but applied to individual customer sales/spend.
Thanks for the great tutorial!
Cheers,
Zach