Zen Cart custom software development, Zen Cart modules, Zen Cart Expert eCommerce with Zen Cart!

Zen Cart Table Discounts

Zen Cart Table Discounts

A Zen Cart™ discounting module for bulk purchases.

Zen Cart has a built-in quantity discounting mechanism (native quantity discounts), which allows you to discount bulk purchases of a single item. There is also my Zen Cart Quantity Discount Module, which allows you to discount bulk purchases of multiple items, grouped by product id, category id or dollars spent. However, there is no easy way to have different discount schedules for different categories, or to link multiple categories together for discounting. For example, suppose you had one discount schedule for category 7, and a completely different discount schedule for category 9. The solutions I suggested in the past were:
  • Simply clone the Quantity Discounts contribution and set up the second discount schedule in the clone.
  • Use Big Chooser, which permits Quantity Discounting

Obviously the first method doesn't scale well. The second method works, but since Big Chooser is designed to do "Buy <some items>, get a discount on <some other items>", it requires a pretty hairy (if I do say so) amount of configuration when you want to discount the entire group of items under consideration. That's why I created Table Discounts.

Background: See the Zen Cart Matrix-o-discounts

Example Discounts: I have provided several examples of Zen Cart Table Discounts discounts.

Relevance: Zen Cart™ 1.3.5 - 1.3.9, 1.5.x
See interoperability for changes required for Edit Orders.

Current Version: 1.5 (version history)

Support Thread: My commercial software is not supported on the Zen Cart forum. Please email me questions instead.

Cost: $60.00 (Note: this low price covers software only for self-installation.)

Buy Now

Would you like to ask me questions before buying? I'm happy to help likely purchasers make the right decision. Please use my contact form.

Installed Cost: $200.00 (Professional installation by That Software Guy)

Installation Difficulty: Moderate (You must write some PHP to configure this mod; there is no Admin panel)

Installation Instructions: click here for installation instructions

Tax Notes: Notes on tax handling

Buy: Buy Table Discounts!
Pre-purchase questions? No problem! Just Please contact me with your question.

FAQ: click here for FAQs

Configuration: The basic configuration of Table Discounts involves adding PHP code to the setup() function in the module, as shown below. No admin panel is available. Many examples of basic configuration are shown in this help file; examples of advanced configuration are also available.

Marketing Text: click here for marketing text

Video: You may watch some discounts being created in Table Discounts in this video:

Promotional Page Download: free from my website (you must buy Table Discounts separately)

Table Discounts is an order total module, so the discount is not visible until the second page of checkout. If you want to see the discount on the shopping cart page (or sidebox), look at Discount Preview.

Bugs: click here for bugs


Table Discounts permits a shop to create table based discounts, grouping products by category, id or manufacturer, and discount purchase levels by percent, a dollar amount per unit, a net dollar amount, or a package final price for the group from which a discount is computed. The number of discounts supported is unlimited.

The discounts themselves are not entered into an admin panel; they are specified by modifying the setup() function in the file includes/modules/order_total/ot_table_discounts.php

Table Discounts is configured by specifying lists of items which are eligible for discounting and then specifying the levels at which discounts occur.

Table Discounts requires you to add these conditions and parameters to the module itself - they are not configured through the admin panel. This sounds complicated, but it's not that bad, and many examples of common discounting practices are provided. Please note that Table Discounts only provides a discount; it does not automatically add items to the cart.

The calling conventions for building a table discount are as follows:

You begin with a text string that describes the discount. So suppose the discount was, "Buy 4 items from Category 3, save 10%. Buy 8 items, save 20%."

Edit includes/modules/order_total/ot_table_discounts.php, and go to the bottom where the setup() function is located. Change it to:

function setup() { 
   $this->add_table("Bulk discounts on category 3");
     $this->set_constraint(CAT, 3);
     $this->set_discount("%", 4, 10, 8, 20);  

The statements "set_discount" and "set_constraint" are called parameter statements. Parameter statements apply to the add_table statement they immediately follow. I have provided a visual cue for this by indenting the parameter statements on this page by three spaces. The following types of parameter statements are currently supported:

  • set_constraint - specifies the items which are eligible for this discount
  • set_negative_constraint - specifies the items which are NOT eligible for this discount
  • set_discount - specifies the table discount
  • set_support - provide additional information on the discount
  • set_group - only apply this discount to members of the listed groups
  • set_constraint_regprice - specifies that items counted towards the constraints must not be on sale or special
  • set_count - indicates that either tiering or case discounts should be used
  • set_policy_lowtohigh - When constraints other than PROD are used, the list of products is processed from highest price to lowest price by default; this command inverts that behavior
  • set_constraint_attrfilter - Allows further filtering of constraints (which items are eligible for the discount) based on an attribute setting
  • set_constraint_name_includes - Allows further filtering of constraints (which items are eligible for the discount) based on a substring of the product's name

So here are four examples, showing the four types of discounts which can be done using Table Discounts.

First, the basic percent discount for larger quantities:
function setup() { 
   $this->add_table("Category 3 Discounts: buy 4, save 10%, buy 8, save 20%");
     $this->set_constraint(CAT, 3);
     $this->set_discount("%", 4, 10, 8, 20);  

Second, a dollars saved per item discount:
function setup() { 
   $this->add_table("Category 3 Discounts: buy 4, save $5 each, buy 8, save $10 each");
     $this->set_constraint(CAT, 3);
     $this->set_discount("$", 4, 5, 8, 10);  

Third, a net dollars saved per tier discount:
function setup() { 
   $this->add_table("Category 3 Discounts: buy 4, get $5 off, buy 8, get $10 off");
     $this->set_constraint(CAT, 3);
     $this->set_discount("$$", 4, 5, 8, 10);  

And lastly, a package final price discount.
function setup() { 
   $this->add_table("Category 3 Discounts: buy 4 for $50, or 8 for $70");
     $this->set_constraint(CAT, 3);
     $this->set_discount("F", 4, 50, 8, 70);  

Detailed Description:

  1. Configuration
    Table Discounts is installed through the Admin interface (Admin > Modules > Order Total > Table Discount).

    This is where the tax settings and sort order are configured.

    Once this is done, the file includes/modules/order_total/ot_table_discounts.php is edited to specify the discounts themselves. The discounts are specified according to the following syntax:

    function setup() {
    $this->add_table(<description >); 
      $this->set_constraint(<discount basis 1>, <id 1> ...  <discount basis n>, <id n>); 
      $this->set_discount(<discount units>, <min quantity 1>, <discount 1>, ... <min quantity n>, <discount n>); 

    "discount basis" is one of PROD, CAT or MANUF (for selection by product id, category id or manufacturer id)
    "id" is the product, category or manufacturer id. Note that category id '*' may be used to select all categories.
    "discount units" is one "%", "$", "$$" or "F".
    (% meaning percent off, $ meaning dollars off per item, $$ meaning an absolute dollar discount off, and F meaning the package final price)

    (Note: your local currency is used if dollars are not your default currency)
    The set_discount and set_constraint commands apply to the add_table command they immediately follow.

    So for example,
    $this->add_table("Quantity discounts on category-3 items");
      $this->set_constraint(CAT, 3);
      $this->set_discount("%", 50, 10, 100, 25);
    would mean "Buy 50-99 category 5 items, get 10% off , buy 100 or more, get 25% off."
  2. Checkout Page User Interface
    Table Discounts is an "Order Total" module, which means that by default, the discount is not shown until the second page of checkout (Payment Information). However, using the Discount Preview module will allow you to show the discount in the shopping cart.

    Depending on your configuration, the second page of checkout will look something like this:

    Zen Cart Checkout Payment Information Page with Table Discounts


Here are some example configurations
$this->add_table("Quantity discounts on category-5 items");
  $this->set_constraint(CAT, 5);
  $this->set_discount("$", 50, 2, 100, 5);
would mean "Buy 50-99 category 5 items, get $2 off each, buy 100 or more, get $5 off each."

$this->add_table("Bulk discounts on product-7");
  $this->set_constraint(PROD, 7);
  $this->set_discount("$$", 10, 5, 20, 12);
would mean "Buy 10-19 of product 7, get $5 off your purchase, buy 20 or more, get $12 off."

$this->add_table("Buy multiple items from manufacturer 8 and save!");
  $this->set_constraint(MANUF, 8);
  $this->set_discount("%", 100, 5, 200, 12);
would mean "Buy 100-199 of products from manufacturer 8, get 5% off, buy 200 or more, get 12% off."

$this->add_table("Any five category 12 items only $20!");
  $this->set_constraint(CAT, 12);
  $this->set_discount("F", 5, 20); 
would mean "Buy five items from category 12, get a discount sufficient to bring the price of this lot down to $20."

The category used in Table Discounts may be the category id at any level, not just the parent category.

Men's Clothing (category 3)
     ---->  Shirts (category 7)
            -------> shirt A     
                     shirt B
                     shirt C 
     ---->  Shoes (category 8)
            -------> shoe A     
                     shoe B
                     shoe C 
     ---->  Hats (category 9)
            -------> hat A     
                     hat B
                     hat C 
In this example, if category 7 were specified, only the shirts would be considered for discounting. If category 3 were specified, shirts, shoes and hats would be considered for discounting. This is different from Quantity Discounts, which only permits parent categories to be used.

What is also different from Quantity Discounts is the ability to specify multiple categories. To discount Shoes and Shirts, mix and match buying 3 get 10% off, you can do

$this->add_table("Mix and match shoes and shirts at a discount");
  $this->set_constraint(CAT, 7, CAT, 8);
  $this->set_discount("%", 3, 10);

To have buy 3 get 10% off, buy 6 get 20% off, buy 12, get 30% off, you simply expand the set_discount command.
$this->add_table("Mix and match shoes and shirts at a discount");
  $this->set_constraint(CAT, 7, CAT, 8);
  $this->set_discount("%", 3, 10, 6, 20, 12, 30);

Applying the maximum discount to all items once the final threshold has been crossed is the type of discounting most retailers want to offer. But there are two other modes of discounting which can be done with table discounts: tiered discounting and case discounting.

Tiered discounting and Case discounting

First, an explanation of terminology.
  • Tiered discounting discounts items with by applying specific discounts to specific counts of products within a single order. If you want one price for the first 10 items, another for the next 20 and another for the next 50, look at tiered discounts.
  • Case discounting only discounts groups of items in specific numeric quantities. If you want to offer special prices for groups of 6, 12 and 24, but no special prices for other multiples, look at case discounting.
Note: cases may be mix and match; they are not limited to a single product. So "by case" pricing can also be thought of as "by collection."

Tiered discounts were added to Table Discounts in version 1.1. Here are some examples of how they can be used.

An easy example first. If you do
function setup() {
       $this->add_table("Discount on movies - 5% off 10 or more"); 
          $this->set_constraint(CAT, 3);
          $this->set_discount("%", 10, 5);
This gives you, "Buy 10 or more, get 5% off all of them.

But what if you only wanted to give 5% off the 10th and higher items? So you had to buy 9 at regular price to qualify for the discount.
function setup() {
       $this->add_table("Discount on movies - discounts on 10 or more, first 9 at regular price"); 
          $this->set_constraint(CAT, 3);
          $this->set_discount("%", 10, 5);

Now a more complicated example. Suppose your discount was:
function setup() {
       $this->add_table("Discount on hardware"); 
          $this->set_constraint(CAT, 1);
          $this->set_discount("%", 20, 10, 50, 20, 100, 25);
This corresponds to the following discount:
20 - 4910%
50 - 9920%
100 + 25%

But suppose your pricing is "tiered," so that the better prices are only available for the items that exceed that tier's quantities.

If you bought 100 items for $10 each, the regular (non-tiered) discount would be $100 * 25%, which would be $250.00.

With tiering, the discounting would be as follows:
19 at 0% off
30 at 10% off = $30
50 at $20% off = $100
1 at 25% off = $2.50
for a total discount of $132.50.

To add tiering, simply add the statement set_count(BY_TIER) to your discount. So the new setup() function would be:
function setup() {
       $this->add_table("Discount on hardware"); 
          $this->set_constraint(CAT, 1);
          $this->set_discount("%", 20, 10, 50, 20, 100, 25);

Suppose instead of 100 $10 items, there was a mix of items. If there are 49 $10 items and 51 $20 items, the tiered discount is (applied highest to lowest) is:
19 $20 items at 0% off $0
30 $20 items at 10% off = $60
2 $20 items at 20% off = $8
48 $10 items at 20% off = $96
1 $10 item at 25% off = $2.50
for a total discount of $166.50.

Some vendors will not want to discount highest to lowest because it means the lowest priced item will attract the greatest discount, which could be confusing or disappointing to customers.

To discount lowest to highest instead, use the command

If the discount was applied lowest to highest, you would have the setup function being:
function setup() {
       $this->add_table("Discount on hardware"); 
          $this->set_constraint(CAT, 1);
          $this->set_discount("%", 20, 10, 50, 20, 100, 25);
and the discounts being:
19 $10 items at 0% off
30 $10 items at 10% off = $30
50 $20 items at 20% off = $200
1 $20 item at 25% off = $5.00
for a total discount of $235.

Note that set_policy_lowtohigh() applies to *all* table discounts; it is a global setting.

Another counting option is provided: by case. For instance, suppose all the products in category 17 are available in mix or match cases of 35, with a 10% case discount, but with quantities less than a full case at no discount.
function setup() {
       $this->add_table("Case discount on items in Category 17"); 
          $this->set_discount("%", 35, 10); 
This would produce the following table:

If you bought 100 items for $10 each, the case discount would be as follows:

30 at 0% off
2 cases (70) at 10% off = $70
for a total of $70 off.

If the discount was $10 per case rather than 10% per item in the case, you could use "$$" discounting, i.e.
function setup() {
       $this->add_table("Case discount on items in Category 17"); 
          $this->set_constraint(CAT, 17);
          $this->set_discount("$$", 35, 10); 
Note that using "$" instead of "$$"
          $this->set_discount("$", 35, 10); 
would discount $10 per item, rather than $10 per case.

If you wanted to discount cases of 35 by $10 and cases of 100 by $50, you could do that too as follows:
function setup() {
       $this->add_table("Case discounts on items in Category 17"); 
          $this->set_discount("$$", 35, 10, 100, 50); 

Installation Instructions:

  1. Back up everything! Try this in a test environment prior to installing it on a live shop.
  2. If you already have the Table Discounts module installed, please deinstall your old copy by going to Admin > Modules > Order Total, selecting "Table Discount" and pressing the "Remove" button. Make a note of your settings so you can apply them to the new version.
  3. Copy the contents of the unzipped folder to the root directory of your shop.
    The names of these files reflect a template name of "custom." If you are using a different template name, please change file paths using "custom" to use your template name instead. Note: If you are using Zen Cart 1.5.5 or higher, your template name will be "responsive_classic" if you have not changed it.
  4. Login to Admin and in Modules > Order Total you will see 'Table Discount' listed along with all the other modules available.
  5. Click on 'Table Discount' to highlight the module and click on 'Install'
  6. Decide on the parameters you wish to use. The easiest way to do this is to open a shopping cart in another window, and just try different discounting models. The discounts are shown on the second step of checkout in "Your Total" under "Table Discounts."
  7. If you wish, follow the guidelines in marketing to advertise your discounts.
  8. If you wish, install a Table Discounts Promotional Page by following the links at the top of this page.

Optional Installation Instructions:

  1. I highly recommend Discount Preview with all my discounting modules. Without Discount Preview, your customers cannot see the price reductions they are entitled to until the second page of checkout (checkout confirmation). Obviously this is a disadvantage, particularly for new customers who need to go through the additional step of creating an account before they can see this information. Sometimes seeing is believing, so here's a video showing Discount Preview in action.

More Examples

You can use Table Discounts to create a segmented group discount. For example, suppose you want to offer a 10% discount off 3 or more category 7 and 8 to customers in one group only.
Create the group in Admin > Customers > Group Pricing, but set the discount amount to 0%. This way, Group Pricing won't do additional discounting for all products. Suppose the group number was 2. Use the "set_group" statement to only allow the discount to group 2 members:
$this->add_table("Mix and match shoes and shirts at a discount");
  $this->set_constraint(CAT, 7, CAT, 8);
  $this->set_discount("%", 3, 10);

On the other hand, if your group discount was already generous, and you only wanted to give this discount to customers not already in a group, you can specify group 0.
$this->add_table("Mix and match shoes and shirts at a discount");
  $this->set_constraint(CAT, 7, CAT, 8);
  $this->set_discount("%", 3, 10);

If you wanted to do a 80% discount on category 7 items for group 2 and a 50% discount for group 3, you would code:
$this->add_table("80% off category 7 items for group 2");
  $this->set_constraint(CAT, 7); 
  $this->set_discount("%", 1, 80);

$this->add_table("50% off category 7 items for group 3");
  $this->set_constraint(CAT, 7); 
  $this->set_discount("%", 1, 50);

To discount 10% for group 5 on categories 1-4, you would do
$this->add_table("10% off category 1-4 items for group 5");
  $this->set_constraint(CAT, 1, CAT, 2, CAT, 3, CAT, 4); 
  $this->set_discount("%", 1, 10);

If you have two products, 230 and 231, that you want to give 10% off for mix and match quantities of 100 or more:
this->add_table("Bulk discounts on product 230 and 231");
  $this->set_constraint(PROD, 230, PROD, 231);
    $this->set_discount("%", 100, 10);

This is not limited to two products; you can go on as long as need be:
this->add_table("Bulk discounts on product 230, 231, 232, and 233");
  $this->set_constraint(PROD, 230, PROD, 231, PROD, 232, PROD, 233);
    $this->set_discount("%", 100, 10);

If you have a default discount for all products but a specific discount for certain products and categories, then arrange your discounts from most specific to most general. Use the selector CAT, '*' to match all categories / all products.
this->add_table("Special bulk discounts on category 12 - save 20%");
  $this->set_constraint(CAT, 12); 
    $this->set_discount("%", 100, 20);

this->add_table("General bulk discounts on all items - save 10%");
  $this->set_constraint(CAT, '*'); 
    $this->set_discount("%", 100, 10);
(Note that support for CAT '*' was added in version 1.1d.)

You can also use CAT '*' to discount all products, with specific exceptions. Here's an example: buy 3 or more items, get 10% off (except category 1, which is the clearance category and is already discounted):
       $this->add_table("Discount all products, buy 3+ save 10%, except clearance"); 
          $this->set_constraint(CAT, '*');
          $this->set_negative_constraint(CAT, 1);
          $this->set_discount("%", 3, 10); 

If you want to limit discounts to only a certain quantity, that can be done too. Here we discount the first 3 of a group of products.
this->add_table("20% off on products 230, 231, 232, and 233 (limit 3)");
  $this->set_constraint(PROD, 230, PROD, 231, PROD, 232, PROD, 233);
    $this->set_discount("%", 1, 20, 4, 0);


What good is having cross selling and upselling specials if you don't advertise them?

Table Discounts may be automatically displayed in two places: on the product info page, and on a separate promotional page. We'll talk about the product info page first.

Customize the tpl_product_info_display.php file to advertise your discounts.
Copy the file includes/templates/template_default/templates/tpl_product_info_display.php into includes/templates/<YOUR_TEMPLATE>/templates

Then add this block of code to the new copy of tpl_product_info_display.php:
   $current_page_base,'templates'). '/tpl_table_discounts_marketing.php');
The placement of this code is a matter of personal preference; try placing it below the product description and adjust to your tastes. It creates a message on your page that advertises the discounts that are applicable to that product.

For example, the following discount
    function  setup() {
       $this->add_table("Discount on movies"); 
          $this->set_constraint(CAT, 46);
          $this->set_discount("%", 5, 3, 10, 5, 20, 8);
would generate this image:
Zen Cart Table Discounts Marketing

The following discount
    function  setup() {
       $this->add_table("Discount on movies"); 
          $this->set_constraint(CAT, 46);
          $this->set_discount("$", 5, 3, 10, 5, 20, 8);
would generate this image:
Zen Cart Table Discounts Marketing

As an alternative, starting in version 1.2, you may create marketing text in sentence form. Add this block of code to the new copy of tpl_product_info_display.php:
   $current_page_base,'templates'). '/tpl_table_discounts_marketing2.php');

The following discount
    function  setup() {
       $this->add_table("Discount on movies"); 
          $this->set_constraint(CAT, 46);
          $this->set_discount("$", 5, 3, 10, 5, 20, 8);

would generate this image:
Zen Cart Table Discounts Marketing

If you would like to have a Table Discounts Promotional Page that describes your store's table discounts as part of your categories sidebox, you may download a copy here.

The promotional page creates a new page for your site. This new page can be accessed via the URL
A link to this page may be added to the categories sidebox, the site footer, or the main page content for your site. See Promotional Pages for more information and ideas.

Table Discounts and Discount Preview

Discount Preview makes Big Chooser pop! It shows the discount on the shopping cart page, instead of making your customers wait until the checkout payment page to see their discounts. Here's a screenshot of the shopping cart page on a cart using Discount Preview and Table Discounts - the discount was $10 off each for a particular item for group 1 members.

Zen Cart Table Discounts and Discount Preview

Discount Preview is sold separately. Buy Discount Preview Now!

Notes on Taxes

If you don't use embedded taxes, and don't have a mix of taxable and tax-free products, and don't have a different rate of tax for shipping, please skip this section.
However, if you any of the above apply to you, please read my Notes on Taxes.

Be sure that the sort order for the Tax module (set in Admin->Modules->Order Total->Tax) is greater than the largest order total sort order, so that your taxes are shown after all discounts. 399 is a good value for most stores.


(new) includes/languages/english/modules/order_total/ot_table_discounts.php
(new) includes/modules/order_total/ot_table_discounts.php
(new) includes/templates/custom/templates/tpl_table_discounts_marketing.php

Formal Syntax of Tables and Parameters

Tables and Parameters, which are specified in the setup() function of ot_table_discounts.php, are the mechanism for configuring a store's discounts.

Note that each parameter is comma separated from the next one. So "discount followed by discount amount" is coded as discount, discount_amount


Discounts always begin by specifying a table. All subsequent parameters (until the next table) apply to this table.


descriptionIs a textual description of the discount. This description is not automatically created the way it is in Better Together or Combination Discounts; it must be added manually. The reason for this is to allow greater flexibility

Parameters - set_constraint

The set_constraint() command specifies the items to which this discount applies.

$this->set_constraint(<required_purchase_quantity 1>[,<required_purchase_quantity 2>,...,<required_purchase_quantity n>]);

is the string PROD, CAT, or MANUF, followed by an identifier (product or category id, or manufacturer id)

<PROD | CAT | MANUF> <product, category or manufacturer identifier >
Note that unlike in Big Chooser, quantities are not specified in the set_constraint parameter in Table Discounts; they are specified in the set_discount parameter.

Parameters - set_discount

The set_discount() command specifies the items or categories whose prices should be reduced if the condition has been met.

$this->set_discount(<discount units>, <discount 1>[,<discount 2>,...,<discount n>]);

discount_unitsis the string "%", "$", "$$", or "F", meaning percent off, dollars off per quantity purchased, net dollars off or package final price for the group.
discountis a quantity followed by a discount amount (the units of which are specified by discount_units above).

Note that package final price discounts behave like case discounts (only groups of items at the specified size(s) are discounted; additional items are not). So if you specify a package final price discount for a group of ten items, and the customer purchases 11, the 11th item is not discounted. Package final price discounting was added in version 1.4.

Note that a package final price discount creates a discount such that the price of the items in question minus the discount is equal to the final price.

Parameters - set_support

The set_support() command provides additional supporting text to describe your promotion. It is completely optional.


textis a text string, which can be plain text or a link

These strings are displayed on your promotional page, and optionally, on your product info page if you customize the file includes/templates/YOUR_TEMPLATE/templates/tpl_table_discounts_marketing.php

Parameters - set_group

The set_group() command specifies that the discount is only available to members of the listed group(s).

$this->set_group(<group 1>[,<group 2>,...,<group n>]);

groupis the group eligible to receive the discount

Note that group 0 is the groupid of customers who are not in a pricing group.

Parameters - set_constraint_regprice

Require items counted towards the constraint not be on sale or special.


Parameters - set_policy_lowtohigh

Normally the list of products meeting the constraints for a discount is processed from highest price to lowest price by default; this command inverts that behavior. This becomes important in tiered and case discounting. For more information on this discounting model, please see tiered discounting and case discounting.


The set_policy_lowtohigh command was added in version 1.1.

Parameters - set_count

The set_count command allows you to specify case or tiered pricing for your discount. For more information on this discounting model, please see tiered discounting and case discounting.


The set_count command was added in version 1.1.

Parameters - set_constraint_attrfilter

The set_constraint_attrfilter() command specifies that the constraint items must also have the listed attributes set to the specified values.

$this->set_constraint_attrfilter(<attribute id 1>,<attribute value 1>[, ... <attribute id n>,<attribute value n>]);

attribute idis the id of the attribute you want set
attribute valueis the value of the attribute you want set

To get these numbers, look in Admin > Catalog > Option Name Manager and Admin > Catalog > Option Value Manager to get the ID and Value for the attributes you want.

Another way to do this is to view the source of your product info page and look at the way the attribute is set up. Here's an example for a dropdown box which allows you to choose USB or PS/2.

If you were to do a view source on this, here's what it would look like:
<h4 class="optionName back"><label class="attribsSelect" for="attrib‐3">Model</label></h4>
<div class="back">
<select name="id[3]" id="attrib-3">
  <option value="9">USB ( +$6.00 )</option>
  <option value="8">PS/2</option>
So to only give the discount for USB, you would use

The following attribute types may be used: dropdown, radio button, checkbox.

If multiple attribute id/value pairs are specified, only one of them needs to be set for an item to be considered to meet the constraint. For example, if you specify id 4, value 9 and id 12, value 7, then any item with either attribute id 4, value 9 OR id 12, value 7 will pass this check.

The set_constraint_attrfilter command was added in version 1.3.

Parameters - set_negative_constraint

The set_negative_constraint() command specifies the items which are excluded from the promotion; they will not be counted towards the condition or included in the discount.

$this->set_negative_constraint(<ignored_purchase 1>[,<ignored_purchase 2>,...,<ignored_purchase n>]);

ignored_purchaseis the string PROD, CAT, or MANUF, followed by an identifier (product or category id, product price or manufacturer id).

<PROD | CAT | | MANUF> <product or category identifier or manufacturer identifier >

Big Spender and Big Chooser users note: The behavior of set_negative_constraint is different in Table Discounts, since the constraints are also the discounted items. This means using set_negative_constraint removes an item from both consideration when counting up constraints or from being discounted.

The set_negative_constraint command was added in version 1.4.

Parameters - set_constraint_name_includes

The set_constraint_name_includes() command specifies that the constraint items must also include the substring specified in their name.

$this->set_constraint_name_includes("some string");

some-stringis the string which you want the name to include

For example, if your discount specifies,
$this->set_constraint_name_includes("case of 100");

And you have two products in your cart:
Big Box - case of 25
Small Box - case of 100

Only the second would attract the discount (assuming all other conditions were satisfied).

The set_constraint_name_includes command was added in version 1.3.

Major Versions

  • Version 1.5 - 12/21/2018 - PHP7 Updates.
  • Version 1.4 - 09/01/2014 - Added set_negative_constraint, package final price discounting.
  • Version 1.3 - 03/02/2014 - Added set_constraint_attrfilter, set_constraint_name_includes.
  • Version 1.2 - 10/01/2013 - Added alternate marketing text; code cleanup.
  • Version 1.1d - 09/18/2013 - Added category "*" (universal match).
  • Version 1.1c - 01/25/2013 - Correction in marketing text.
  • Version 1.1b - 08/20/2010 - Correction in marketing text.
  • Version 1.1 - 06/04/2010 - Tiered and case discounts.
  • Version 1.0.1 - 04/01/2010 - First Release; Standard linkages for product and category.


  • If you are using Zen Cart 1.5.x and Edit Orders 4.x and Table Discounts, you must make the following change:
    Create a file called admin/includes/functions/extra_functions/table_discounts_lookups.php
    It should contain this code:
    if (! function_exists('zen_get_products_manufacturers_id')) { 
      function zen_get_products_manufacturers_id($product_id) {
        global $db;
        $product_query = "select p.manufacturers_id
                          from " . TABLE_PRODUCTS . " p
                          where p.products_id = '" . (int)$product_id . "'";
        $product =$db->Execute($product_query);
        return $product->fields['manufacturers_id'];


  • For recalculate tax = Standard, carts using Edit Orders 4.3.1 will need to change the process() function in the code file in includes/modules/order_total as follows:
                   if ($this->calculate_tax != 'VAT') {
                      $order->info['total'] -= $od_amount[$key];
                   if (!IS_ADMIN_FLAG) {
                      if ($this->calculate_tax != 'VAT') {
                         $order->info['total'] -= $od_amount[$key];
  • Users wishing to sort native discounts (such as Coupons or Group Discounts) after my discounts, with tax recalculation, should look at this page.


Q: I'm using a category based discount and it's not working!
A: Please see the Category Issues page for solutions.

Q: How do I install this software?
A: If you've never installed a Zen Cart mod before, please read my Guide to Mod Installation on Zen Cart.

Q: I can't seem to get Table Discounts to work. What am I doing wrong?
A: Please check the following things:
  • Go to Admin > Modules > Order Total. Do you see Table Discounts? If not, then you haven't installed it. Follow the README.
  • If you do see it, the circle at the right hand end of the row for Table Discounts should be green. If it's not green, reinstall it.
  • If you're using category discounts, see the previous FAQ question.
  • Re-read my Guide to Mod Installation on Zen Cart.

Q: Do package final price discounts reduce the unit price of items?
A: No! A package final price discount simply creates a discount such that the price of the items in question minus the discount is equal to the package final price. For example, here is a demonstration of "Buy 4 movies for $100" discount shown on the shopping cart page by Discount Preview. Here's the code:
    function  setup() {
       $this->add_table("Discount on movies- 4 for $100"); 
          $this->set_constraint(CAT, 3);
          $this->set_discount("F", 4, 100);
Zen Cart Final Price Discount using Table Discounts

Q: How do I tell if my stock is organized into subcategories?
A: In the Admin page, go to Catalog > Categories/Products, and click on the category you're not sure about. If the entries that appear on the next page have file folders to the left of their names, then these are subcategories. If the products are directly below these folders, then these folders are the parent folder numbers you will use for category inclusions, exclusions and special discounts. If what is below these subcategories is more subcategories, continue drilling down until you get to products, and then go back one level.

Q: Why is there a Table Discounts contribution in the first place?
A: Zen Cart has a number of intrinsic discounting mechanisms: coupons, specials, sales, group discounts, discounts via the products price manager, etc.
While each of these fills a need, some retailers have different discounting needs that cannot easily be met by any of these features. The Table Discounts contribution was designed to meet these needs.

My Zen Cart Quantity Discount Module, allows you to create a single table discount. My Zen Cart Big Chooser Module, allows you to create table discounts, but with a very verbose, tedious syntax, since the real intention of Big Chooser is to create "Buy these items, get a discount on those other items" type discounts. So I mixed the two to create Table Discounts.

Q: How do I find out the manufacturer id so I can use MANUF?
A: See Manufacturers in Zen Cart for some techniques.

Q: What is the Products Price Manager?
A: The Products Price Manager implements Zen Cart's native Quantity Discounting mechanism. Go to Admin > Catalog > Categories/Products, select a product, and press the green $ sign. You are now in Products Price Manager.

Q: Is the Table Discounts contribution related to the native Quantity Discounting feature in Products Price Manager?
A: No. The Table Discounts contribution has its own configuration (through the setup function), and is completely separate from the Products Price Manager.

Q: I have a table on my product info screen that looks like this (below). Is this the Table Discounts Contribution?
Zen Cart Native Quantity Discounts
A: No - this is the native Quantity Discounts mechanism. Go to Admin > Catalog > Categories/Products and find the product this that shows this table. Press the green $ to enter Products Price Manager, and delete these discounts; they are separate from (and will be applied in addition to) any discounts you configure in the Table Discounts Contribution.

The Table Discounts Contribution's marketing text is different; examples are provided in the marketing text section.

Q: Why didn't you put all the configuration for Table Discounts in the Admin panel?
A: There are an endless number of combinations and permutations of how people want discounting to work. Rather than design a complicated user interface to present all these options, I have provided a framework that anyone with at least a beginner's knowledge of PHP should be able to extend.

Q: I would like my discounts to show up in the shopping cart. Why don't they?
A: The way the Order Total modules work is that they show up at checkout time. However, if you require the discounts to show up in the shopping cart, you may wish to consider purchasing the Discount Preview module for $30.

Alternately, you can indicate that you have a table discount policy by adding to TEXT_INFORMATION in includes/languages/english/shopping_cart.php, and inform the user that the discounts will be calculated (and visible) at checkout time. Additionally, changing SUB_TITLE_SUB_TOTAL in the same file to something like 'Sub-Total BEFORE Discount' will emphasize the fact that a discount will be added at checkout time.


The following Table Discounts extensions are available: I charge a fee for each of these extensions. Contact me for details.

I charge a fee of $60 for Table Discounts. Buy Now!
The fee covers software only; installation is extra if you require help.