When developing loyalty programs or membership systems in WooCommerce, you often need to know how much a specific customer has spent on your site. Fortunately, WooCommerce provides a convenient built-in function to retrieve this information: wc_get_customer_total_spent( $user_id ). Let’s delve into how this function works and how you can use it in your projects.
Using the Built-in WooCommerce Function
The simplest way to get a customer’s total spending is by using the wc_get_customer_total_spent function. This function creates a WC_Customer object and calls its get_total_spent method.
/**
* 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();
}
As shown in the source code above, this core function simplifies the process by handling the heavy lifting for you. It retrieves the total spending as a decimal string, which can then be used for logic checks or display.
How WooCommerce Calculates Total Spending
Under the hood, the get_total_spent method implements an efficient caching mechanism. It first checks for a user meta field named _money_spent. If this field exists, it returns the value immediately. If not, it executes a database query to sum the totals of all successful orders placed by the user, saves the result in _money_spent for future use, and then returns the value. This caching significantly improves performance, especially for sites with many orders.
/**
* 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(
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
)
);
if ( ! $spent ) {
$spent = 0;
}
update_user_meta( $customer->get_id(), '_money_spent', $spent );
}
return wc_format_decimal( $spent, 2 );
}
Which Order Statuses Are Included?
By default, WooCommerce only includes orders with “paid” statuses—typically “processing” and “completed”—in the total spending calculation. If you need to include other statuses (like “on-hold”), you can modify the applicable statuses using the woocommerce_order_is_paid_statuses filter.
Practical Application: VIP Messaging
One common use for this function is to identify and reward loyal customers. For example, if a user’s total spending exceeds $500, you can display a special VIP message on their account dashboard and offer them exclusive access to certain products.
add_action('woocommerce_account_dashboard', function ()
{
$user_id = get_current_user_id();
if (wc_get_customer_total_spent($user_id) > 500) {
echo '<div class="woocommerce-message"><a class="button" href="/shop/vip">View VIP Exclusive Products</a>Congratulations! You are one of our valued VIP members.</div>';
}
});
For high-traffic websites, querying the database for spending can be resource-intensive. In such cases, consider using the spending data to periodically adjust user roles (e.g., to a “VIP” role) and then perform logic checks based on the role instead of recalculating the total spending on every page load. This further optimizes your site’s performance while maintaining complex loyalty logic.
