Quickly identify your top-paying customers and get the total amount spent for each in WooCommerce. Perfect for a VIP rewards program.
WooCommerce is full of unknown gems for developers. For example, there are some core functions that calculate pretty complex data, and these functions are mainly “public” so that WooCommerce developers can reuse them for their own purposes.
Today, let’s take a look at the wc_get_customer_total_spent( $user_id ) WooCommerce PHP function.
As you can guess by its name, this function returns the total amount spent by a given customer identified by their user ID. There is no need to loop through user orders to add up totals and return a final sum — WooCommerce already has you covered.
So, let’s take a deeper look at the syntax, meaning, and usage of wc_get_customer_total_spent.
You can find the wc_get_customer_total_spent function under woocommerce\includes\wc-user-functions.php. Clearly, it’s a function that gets a user ID and returns the total spent by that user as a string:
/**
* Get total spent by customer.
*
* @param int $user_id User ID.
* @return string
*/
function wc_get_customer_total_spent( $user_id ) {
$customer = new WC_Customer( $user_id );
return $customer->get_total_spent();
}
The first question that comes to mind is which order statuses are counted toward the total amount spent?
The answer might be inside the get_total_spent function in woocommerce\includes\class-wc-customer.php:
/**
* Return how much money this customer has spent.
*
* @return float
*/
public function get_total_spent() {
return $this->data_store->get_total_spent( $this );
}
/**
* Return how much money this customer has spent.
*
* @since 3.0.0
* @param WC_Customer $customer Customer object.
* @return float
*/
public function get_total_spent( &$customer ) {
$spent = apply_filters(
'woocommerce_customer_get_total_spent',
get_user_meta( $customer->get_id(), '_money_spent', true ),
$customer
);
if ( '' === $spent ) {
global $wpdb;
$statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$spent = $wpdb->get_var(
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
apply_filters(
'woocommerce_customer_get_total_spent_query',
"SELECT SUM(meta2.meta_value)
FROM $wpdb->posts as posts
LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
LEFT JOIN {$wpdb->postmeta} AS meta2 ON posts.ID = meta2.post_id
WHERE meta.meta_key = '_customer_user'
AND meta.meta_value="" . esc_sql( $customer->get_id() ) . ""
AND posts.post_type="shop_order"
AND posts.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
AND meta2.meta_key = '_order_total'",
$customer
)
// phpcs:enable
);
if ( ! $spent ) {
$spent = 0;
}
update_user_meta( $customer->get_id(), '_money_spent', $spent );
}
return wc_format_decimal( $spent, 2 );
}
Finally, we have the full picture of how the wc_get_customer_total_spent function works:
First it checks if the customer/user has _money_spent metadata. If not, there’s no need to query the database.
If _money_spent is null, the function queries the database for all orders placed by the customer ID. The only order statuses to be counted are wc_get_is_paid_statuses ones. If you do a file search for that function, you’ll see that by default it only includes completed and processing order statuses, unless you’ve added custom order statuses to the paid statuses array
After the database call, the total sum is calculated and stored it in the _money_spent customer meta, so that next time the function can run faster by avoiding yet another query.
An interesting observation:get_total_spent returns a floating-point number with two decimals by default (unless you specify otherwise via the WooCommerce settings or a PHP filter hook), while wc_get_customer_total_spent declares that the total is returned as a string. That’s a mystery! Probably a mistake, too, as it should definitely be a float.
Clearly, wc_get_customer_total_spent can be really useful for a store with an active and established customer base.
A good use case for wc_get_customer_total_spent that immediately comes to mind is a VIP section dedicated to customers who have spent more than a given amount. You could display thank you messages, special offers, unlock benefits, and create targeted VIP marketing messages.
A good place to display a VIP status or message is the WooCommerce “My Account dashboard page” and header notification bar for logged-in customers. Then your VIP customers will see a special notice just for them when they log in.
Here’s an example:
/**
* @snippet Show Notice If Customer Spent > $500 @ My Account
* @how-to Get CustomizeWoo.com FREE
* @author Rodolfo Melogli
* @compatible WooCommerce 6
* @donate $9 https://businessbloomer.com/bloomer-armada/
*/
add_action( 'woocommerce_account_dashboard', 'bbloomer_my_account_notice_if_customer_spent' );
function bbloomer_my_account_notice_if_customer_spent() {
$user_id = get_current_user_id();
if ( wc_get_customer_total_spent( $user_id ) > 500 ) {
echo '<div class="woocommerce-message"><a class="button" href="https://cdn.poststatus.com/shop/vip">Browse VIP-only products</a> Congratulations, you are a VIP member!</div>';
}
}
If the customer has spent more than $500, this message will show in the My Account > Dashboard page
WooCommerce by default has a single currency, so wc_get_customer_total_spent may not be usable with multi-currency stores without a special workaround. Have you encountered this situation and come up with a solution? Let us know in the comments.
Learn from others. Grow your business. Connect with a community of like-minded developers and builders who freelance, run agencies and build really cool products and sites in the WooCommerce ecosystem.