How to Retrieve the Total Amount Spent by a User in WooCommerce

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.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *