I was wondering whether anyone could shed some light on how Cart Throb handles taxes on price modifiers? Are they tax inclusive or exclusive? We're about to launch and just spotted an anomaly in how taxes are handled.

We're charging a global tax rate (UK VAT @ 20%) on all products, and entering product prices ex VAT. Trying to set up a product with 3 options however suggests that taxes are either being ignored or incorrectly calculated. It could also be a combination of incorrect tags on my part :-)

The scenario is this:

  • Base price: entered as £8 ex VAT
  • Modifiers: entered as £0/£2/£7 - again, ex VAT.

I can use this code

{exp:cartthrob:item_options entry_id="{entry_id}"}
<div class="option">
  <label for="packsize">Options:</label>
    <div class="option-input">
      {select id="packsize"}
      <option {selected} value="{option_value}" data-price="{price:plus_tax}">{option_name}</option>

and the data-price attribute shows the price uplift with tax included. This suggests the modified prices should be entered ex. VAT. When I add to the basket though, VAT is added to the base price only and not the uplift.

So a price with £8 base + £7 modifier only has tax on the £8 giving a total of £16.60 instead of £18. My cart field is using {item_price:plus_tax}.

Has anyone had experience with this?

  • Having updated the site to CT2.6, there is a new tag item_tax. This still shows the tax on the base price only, so I'm guessing this is a bug. Will raise with Cart Throb. Jul 21, 2014 at 9:23
  • I've spoken with Chris at Cart Throb today and this does appear to be a bug. He's going to look into it, so guess either he or I will update this thread with the fix. Jul 25, 2014 at 16:30
  • Also seeing this same issue with 2.6, any idea on when it'll be fixed?
    – Michael P
    Jul 29, 2014 at 3:24

2 Answers 2


This is a bug in 2.6 that'll be fixed in a later release, thanks for Chris at CartThrob for sorting it out.

In the file third_party/cartthrob/cartthrob/core/Cartthrob_item.php on line 566, change:

$tax = $plugin->get_tax($this->base_price(), $this);


$tax = $plugin->get_tax($cost, $this);

And your tax calculations will be correct.

  • Interesting...there was no mention of any changes to core files from my call. This would make more sense though than my answer. Jul 30, 2014 at 7:30
  • We've checked this on another site today, and this does indeed work :-) Jul 30, 2014 at 12:31
  • I also used this recently. I can confirm that you still need to apply this patch even to the 2.6 release! I am contacting cartthrob now to see if they'll include it.
    – John Hunt
    Sep 5, 2014 at 13:43
  • Upgraded to 2.6 yesterday and just spent a good 4 hours trying to track this down! Thanks for sharing the fix, but wish CT could have included this in an updated release :(
    – Kenny
    Sep 23, 2014 at 16:18

Here's the answer I got posted directly into our site based on our help chat with Cart Throb. It's a one page does it all example, but well commented.

There's been no changes made to core (CT didn't have FTP access), and this was posted in after we closed the skype call, so I haven't had the chance to talk it through with them. I think the only change as far as I can tell is the option price field being option_price and not price:plus_tax.

The other difference I can see is that we were trying to output the tax applicable to each line item, whereas this example simply calculates a % amount, based on the rate set in the settings. So perhaps at a line item level, the calculation is incorrect, but at a cart level, it is correct. This seems a little inconsistent but must admit I haven't had an opportunity to test this fully in our environment.

<title>Tax Test</title>

<h1>Single Page Store</h1>
<p>This single page is an example of how you can use one page to add, update, and delete items, as well as checkout. 
    This is the most in depth single page sample 


{!-- the submitted_order_info tag outputs information from the last attempted order.
    Even if the customer leaves this page and returns, the information from the customer's 
    last attempted purchase will be output. 
    <div class="store_block">
        {if authorized}
        {!-- This content displays if the purchase was successful--}
            Your transaction is complete!<br />
            Transaction ID: {transaction_id}<br />
            Your total: {cart_total}<br />
            Your order ID: {order_id}
        {!-- This content displays if the purchase is only partly completed--}
        {if:elseif processing}
            Your transaction is being processed!<br />
            Transaction ID: {transaction_id}<br />
            Your total: {cart_total}<br />
            Your order ID: {order_id}
        {if:elseif declined}
        {!-- This content displays if the purchase was declined--}
            Your credit card was declined: {error_message}
        {if:elseif failed}
        {!-- This content displays if the purchase completely fails--}
            Your payment failed: {error_message}

{!-- ADD A PRODUCT --}
<div class="store_block">
<h2>Add Products</h2>
{!-- outputting products stored in one of the "products" channels. 
    Product channels are no different than standard channels. --}
{exp:channel:entries channel="products" limit="10"}
         The add_to_cart_form adds 1 or more of a product to the cart

        return: the page the customer will be redirected to after adding this item to the cart
        entry_id: the product's entry_id

            Product name: {title} Price: {pm_base_price}<br />
            Quantity: <input type="text" name="quantity" size="5" value="" /> 
            <br />
            {exp:cartthrob:item_options entry_id="{entry_id}"}
            {if dynamic}
            <div class="control-group">
                <label class="control-label" for="{option_field}">{option_label}</label>
                <div class="controls">
               {if options_exist}
               <div class="control-group">
                  <label class="control-label" for="{option_field}">{option_label}</label>
                   <div class="controls">
                   {select class="input-medium"} 
                      <option {selected} value="{option_value}">
                      {option_name}{if option_price_numeric != 0} +{option_price}{/if}

            <input type="submit" value="Add to Cart">

<div class="store_block">
<h2>Cart Contents</h2>

{!-- cart_items_info outputs information about your current cart, including products in the cart, weight, and prices. 
    you can combine this with update_cart_form, to output cart item data, and update cart info

        {if no_results}
            <p>There is nothing in your cart</p>
    {!-- outputting content that's only applicable for the first item. --}
    {if first_row}
        {!-- adding an update_cart_form to the first row. --}
        {!-- update_cart_form allows you to edit the information of one or more items in the cart at the same time
            as well as save customer information, and shipping options. --}

        <h3>Customer Info</h3>
        {!-- customer_info outputs customer info that is current stored in session.
            update_cart_form, checkout_form, save_customer_info form and other forms
            can all save customer data.

            First Name: <input type="text" name="first_name" value="{customer_first_name}" /><br />
            Last Name: <input type="text" name="last_name" value="{customer_last_name}" /><br />
            Email Address:  <input type="text" name="email_address" value="{customer_email_address}" /><br />
            State: <input type="text" name="state" value="{customer_state}" /><br />
            Country: <input type="text" name="country_code" value="{customer_country_code}" /><br />
            Zip: <input type="text" name="zip" value="{customer_zip}" /><br />
                    <td colspan="2">Quantity</td>
                    {!-- you can reference products by entry_id and row_id. If you sell configurable 
                        items (like t-shirts with multiple sizes) you should use row_id to edit and 
                        delete items, otherwise, all items with that entry id
                        are affected, regardless of configuration --}
                    <input type="text" name="quantity[{row_id}]" size="2" value="{quantity}" />
                    {!-- This deletes one item (row_id) at a time--}
                    <input type="checkbox" name="delete[{row_id}]"> Delete this item
            {if last_row}
            {!-- outputting content that's only applicable for the last item. --}
                        {!-- these are just some of the variables available within the cart_items_info tag --}
                            Subtotal: {cart_subtotal}<br />
                            Shipping: {cart_shipping}<br />
                            Tax: {cart_tax}<br /> 
                            {!--tax is updated based on user's location. To create a default tax price, set a default tax region in the backend --}
                            Shipping Option: {shipping_option}<br />
                            Tax Name: {cart_tax_name}<br />
                            Tax %: {cart_tax_rate}<br />
                            Discount: {cart_discount}<br />
                            <strong>Total: {cart_total}</strong>
                            {!-- total quantity of all --}
                            Total Items: {exp:cartthrob:total_items_count}<br />
                            {!-- total --}
                            Total Unique Items: {exp:cartthrob:unique_items_count}
                    <td colspan="2">&nbsp;</td>
        <input type="submit" value="Update Cart" />


It's also worth adding that they guys at Cart Throb are really helpful. The support sessions are paid and booked in advance, but a half-hour session means you can talk through your scenario with another developer who really understands the product.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.