Compatibility Notice: The following article and code applies to pre-WooCommerce 2.1 only. It is not compatible with WooCommerce 2.1+
As of version 1.6.5.2 at least, WooCommerce does not provide a way to automatically calculate the Line Subtotal and Line Total values for a given product quantity, when creating or updating an order through the Order Admin:
As shown in the above image, there’s a button to calculate the line taxes for the order items, as well as a button to calculate the order totals based on all the line items, but no way of automatically calculating the line totals based on each items quantity. There’s probably a perfectly good explanation for this, though I’ll admit I don’t know what it is. Perhaps there’s simply not enough information to automatically determine the line totals from the admin in all possible cases, so if the shop manager wants to edit the quantity, they must calculate the line totals themselves. For the simple case of the line totals being equal to product price * product quantity, however, it does seem possible, and would be a useful convenience to have. I provide one possible implementation in the remainder of this article.
The Approach
The basic approach taken is to largely follow the pattern used by the ‘Calc Line Tax’ button: create a new ‘Calc Line Totals’ button which highlights the line total/subtotal fields on hover, and performs an AJAX request for each order line item, allowing the calculation code to be implemented in PHP where it belongs. For the total/subtotal calculation, we will make use of the WC_Cart
class, as the logic it contains is quite complex, and not something that we’d like to have to duplicate unless absolutely necessary. Luckily, although perhaps not originally intended for this purpose, the WC_Cart
does seem to get the job done for us. As usual, I’ll cover some code highlights, and link to a full working plugin implementation, so skip down below if you don’t necessarily care about the nitty-gritty.
The Implementation
Since there is no WordPress action available for adding those buttons, the first step is to add our new ‘Calc Line Totals’ button via a JavaScript call:
$('#woocommerce-order-items .buttons-alt').prepend('<button type="button" class="button calc_line_totals">Calc line totals ↑</button>');
Clicking the button will invoke a bunch of JavaScript will loop through the order items, and most importantly perform an AJAX post with the item information to fetch, and then set, the line item totals:
var data = { action: 'woocommerce_calc_line_totals', item_id: $row.find('input.item_id').val(), item_variation: item_variation.length ? $(item_variation[0]).val() : 0, item_quantity: $row.find('input.quantity').val() }; $.post( "/wp-admin/admin-ajax.php", data, function(response) { var result = jQuery.parseJSON( response ); $row.find('input.line_subtotal').val( result.line_subtotal ); $row.find('input.line_total').val( result.line_total ); });
We add an action to handle that AJAX request, instantiate the WC_Cart
class, load it up with the current product, and tell it to calculate the totals. The totals are then returned in the AJAX response:
add_action( 'wp_ajax_woocommerce_calc_line_totals', 'wc_ajax_calc_line_totals' ); public function wc_ajax_calc_line_totals() { $item_id = isset( $_POST['item_id'] ) ? esc_attr( $_POST['item_id'] ) : null; $item_variation = isset( $_POST['item_variation'] ) ? esc_attr( $_POST['item_variation'] ) : null; $item_quantity = isset( $_POST['item_quantity'] ) ? esc_attr( $_POST['item_quantity'] ) : null; // Get product details if ( $item_variation ) $_product = new WC_Product_Variation( $item_variation ); else $_product = new WC_Product( $item_id ); // use the cart to calculate the line totals $cart = new WC_Cart(); $cart->cart_contents[] = array( 'product_id' => $item_id, 'variation_id' => $item_variation, 'variation' => '', 'quantity' => $item_quantity, 'data' => $_product ); $cart->calculate_totals(); echo json_encode( array( 'line_subtotal' => $cart->cart_contents[0]['line_subtotal'], 'line_total' => $cart->cart_contents[0]['line_total'] ) ); }
The returned totals are set by that JavaScript AJAX response handler from above, and with that we should be good!
Excellent as always! Very useful (in fact the owner of the company I’m working with… my wife… was asking for this functionality last night), works seamlessly for all of our products.
Thank you! 🙂
Cool! It’s important to keep the boss happy, doubly so when that’s also the wife!
Just a quick note, and this may be me using this incorrectly, but I am running woocommerce 1.6.6 and when i click the calc line totals button (after installing the plugin attached in this post) it erases the subtotal box so that the price appears to be $0, which of course makes the line total $0 as well.
I know that WooCommerce 2.0 will have the ability to automatically update line totals, so if this isn’t worth your time I completely understand, but I did want to make you aware so that if there is an error in the code, or in my implementation, it would at least available to others.
Hey Keith, thanks for pointing this out; it’s not something I’ve experienced, or seen in my client’s shop that I originally wrote this for, but I’ll watch out for it
Excellent work. Works a treat. Cheers, essential feature!
Just wanted to say thanks for the plugin download – you’re a lifesaver with that one! My client has to manually edit orders and it was a frustration not to be able to automatically calculate quantity totals automatically. Now they can!
Thanks again 🙂
Pete
Found this site after two months of struggle by updating totals manually… Installed and worked like a charm! Kudos! Thank you for your outstanding work and thank you for sharing it!
Attila
Hey Justin,
Great plugin!
I installed it and it worked great….once.
Am I missing something? I enter in the quantity then price but it doesn’t calculate the total.
Any assistance would be greatly appreciated.
Thanks!!
Hey Mark, this all has totally changed as of WooCommerce 2.1, and needs to be redone. It’s just not something that I’ve had the time to tackle quite yet. I’ll add a notice to the top of that post so that folks are aware. Sorry about this!