November 4, 2019: Fixed notices caused by indirect modification of an overloaded element.
December 10, 2018: Added a proper plugin header.
December 1, 2018: Updated to support Gravity Forms 2.4.
November 19, 2014: Updated to support decimal quantities. Props daniaux!
April 1, 2014: Fixed issue where single product fields with no quantity input were not calculated.
March 17, 2014: Fixed issue where option fields of the radio input type were not included in the generated merge tag string.
November 20, 2013: Fixed issue where "Subtotal" merge tag was not displaying in Formula merge tag drop down until it had been added manually. Thanks to @realph for helping track this bug down.
October 9, 2013: Fixed issue where checkbox option fields with ten or more inputs were not being calculated correctly.
September 12, 2013: Fixed issue with Single Product fields when the "Disable Quantity" option was enabled.
September 11, 2013: Fixed issue where checkbox option fields were not correctly calculated.
Stop! There's a better way.
This snippet is available as a plugin with Gravity Perks, a suite of over 33 premium Gravity Forms plugins!
<?php | |
/** | |
* --- STOP! --- | |
* Get the latest version: | |
* https://gravitywiz.com/documentation/gravity-forms-ecommerce-fields/ | |
* ------------- | |
* | |
* Calculation Subtotal Merge Tag | |
* | |
* Adds a {subtotal} merge tag which calculates the subtotal of the form. | |
* | |
* This merge tag can only be used within the "Formula" setting of Calculation-enabled fields (i.e. Number, Calculated Product). | |
* | |
* @version 1.3 | |
* @author David Smith <david@gravitywiz.com> | |
* @license GPL-2.0+ | |
* @link http://gravitywiz.com/subtotal-merge-tag-for-calculations/ | |
* @copyright 2018 Gravity Wiz | |
* | |
* Plugin Name: Gravity Forms Subtotal Merge Tag | |
* Plugin URI: https://gravitywiz.com/subtotal-merge-tag-for-calculations/ | |
* Description: Adds a {subtotal} merge tag which calculates the subtotal of the form. | |
* Author: Gravity Wiz | |
* Version: 1.3 | |
* Author URI: http://gravitywiz.com | |
*/ | |
class GWCalcSubtotal { | |
public static $merge_tag = '{subtotal}'; | |
function __construct() { | |
// front-end | |
add_filter( 'gform_pre_render', array( $this, 'maybe_replace_subtotal_merge_tag' ) ); | |
add_filter( 'gform_pre_validation', array( $this, 'maybe_replace_subtotal_merge_tag_submission' ) ); | |
// back-end | |
add_filter( 'gform_admin_pre_render', array( $this, 'add_merge_tags' ) ); | |
} | |
/** | |
* Look for {subtotal} merge tag in form fields 'calculationFormula' property. If found, replace with the | |
* aggregated subtotal merge tag string. | |
* | |
* @param mixed $form | |
*/ | |
function maybe_replace_subtotal_merge_tag( $form, $filter_tags = false ) { | |
foreach( $form['fields'] as &$field ) { | |
if( current_filter() == 'gform_pre_render' && rgar( $field, 'origCalculationFormula' ) ) | |
$field['calculationFormula'] = $field['origCalculationFormula']; | |
if( ! self::has_subtotal_merge_tag( $field ) ) | |
continue; | |
$subtotal_merge_tags = self::get_subtotal_merge_tag_string( $form, $field, $filter_tags ); | |
$field['origCalculationFormula'] = $field['calculationFormula']; | |
$field['calculationFormula'] = str_replace( self::$merge_tag, $subtotal_merge_tags, $field['calculationFormula'] ); | |
} | |
return $form; | |
} | |
function maybe_replace_subtotal_merge_tag_submission( $form ) { | |
return $this->maybe_replace_subtotal_merge_tag( $form, true ); | |
} | |
/** | |
* Get all the pricing fields on the form, get their corresponding merge tags and aggregate them into a formula that | |
* will yeild the form's subtotal. | |
* | |
* @param mixed $form | |
*/ | |
static function get_subtotal_merge_tag_string( $form, $current_field, $filter_tags = false ) { | |
$pricing_fields = self::get_pricing_fields( $form ); | |
$product_tag_groups = array(); | |
foreach( $pricing_fields['products'] as $product ) { | |
$product_field = rgar( $product, 'product' ); | |
$option_fields = rgar( $product, 'options' ); | |
$quantity_field = rgar( $product, 'quantity' ); | |
// do not include current field in subtotal | |
if( $product_field['id'] == $current_field['id'] ) | |
continue; | |
$product_tags = GFCommon::get_field_merge_tags( $product_field ); | |
$quantity_tag = 1; | |
// if a single product type, only get the "price" merge tag | |
if( in_array( GFFormsModel::get_input_type( $product_field ), array( 'singleproduct', 'calculation', 'hiddenproduct' ) ) ) { | |
// single products provide quantity merge tag | |
if( empty( $quantity_field ) && ! rgar( $product_field, 'disableQuantity' ) ) | |
$quantity_tag = $product_tags[2]['tag']; | |
$product_tags = array( $product_tags[1] ); | |
} | |
// if quantity field is provided for product, get merge tag | |
if( ! empty( $quantity_field ) ) { | |
$quantity_tag = GFCommon::get_field_merge_tags( $quantity_field ); | |
$quantity_tag = $quantity_tag[0]['tag']; | |
} | |
if( $filter_tags && ! self::has_valid_quantity( $quantity_tag ) ) | |
continue; | |
$product_tags = wp_list_pluck( $product_tags, 'tag' ); | |
$option_tags = array(); | |
foreach( $option_fields as $option_field ) { | |
if( is_array( $option_field['inputs'] ) ) { | |
$choice_number = 1; | |
$inputs = $option_field->inputs; | |
foreach( $inputs as &$input ) { | |
//hack to skip numbers ending in 0. so that 5.1 doesn't conflict with 5.10 | |
if( $choice_number % 10 == 0 ) | |
$choice_number++; | |
$input['id'] = $option_field['id'] . '.' . $choice_number++; | |
} | |
$option_field->inputs = $inputs; | |
} | |
$new_options_tags = GFCommon::get_field_merge_tags( $option_field ); | |
if( ! is_array( $new_options_tags ) ) | |
continue; | |
if( GFFormsModel::get_input_type( $option_field ) == 'checkbox' ) | |
array_shift( $new_options_tags ); | |
$option_tags = array_merge( $option_tags, $new_options_tags ); | |
} | |
$option_tags = wp_list_pluck( $option_tags, 'tag' ); | |
$product_tag_groups[] = '( ( ' . implode( ' + ', array_merge( $product_tags, $option_tags ) ) . ' ) * ' . $quantity_tag . ' )'; | |
} | |
$shipping_tag = 0; | |
/* Shipping should not be included in subtotal, correct? | |
if( rgar( $pricing_fields, 'shipping' ) ) { | |
$shipping_tag = GFCommon::get_field_merge_tags( rgars( $pricing_fields, 'shipping/0' ) ); | |
$shipping_tag = $shipping_tag[0]['tag']; | |
}*/ | |
$pricing_tag_string = '( ( ' . implode( ' + ', $product_tag_groups ) . ' ) + ' . $shipping_tag . ' )'; | |
return $pricing_tag_string; | |
} | |
/** | |
* Get all pricing fields from a given form object grouped by product and shipping with options nested under their | |
* respective products. | |
* | |
* @param mixed $form | |
*/ | |
static function get_pricing_fields( $form ) { | |
$product_fields = array(); | |
foreach( $form["fields"] as $field ) { | |
if( $field["type"] != 'product' ) | |
continue; | |
$option_fields = GFCommon::get_product_fields_by_type($form, array("option"), $field['id'] ); | |
// can only have 1 quantity field | |
$quantity_field = GFCommon::get_product_fields_by_type( $form, array("quantity"), $field['id'] ); | |
$quantity_field = rgar( $quantity_field, 0 ); | |
$product_fields[] = array( | |
'product' => $field, | |
'options' => $option_fields, | |
'quantity' => $quantity_field | |
); | |
} | |
$shipping_field = GFCommon::get_fields_by_type($form, array("shipping")); | |
return array( "products" => $product_fields, "shipping" => $shipping_field ); | |
} | |
static function has_valid_quantity( $quantity_tag ) { | |
if( is_numeric( $quantity_tag ) ) { | |
$qty_value = $quantity_tag; | |
} else { | |
// extract qty input ID from the merge tag | |
preg_match_all( '/{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/mi', $quantity_tag, $matches, PREG_SET_ORDER ); | |
$qty_input_id = rgars( $matches, '0/1' ); | |
$qty_value = rgpost( 'input_' . str_replace( '.', '_', $qty_input_id ) ); | |
} | |
return floatval( $qty_value ) > 0; | |
} | |
function add_merge_tags( $form ) { | |
$label = __('Subtotal', 'gravityforms'); | |
?> | |
<script type="text/javascript"> | |
// for the future (not yet supported for calc field) | |
gform.addFilter("gform_merge_tags", "gwcs_add_merge_tags"); | |
function gwcs_add_merge_tags( mergeTags, elementId, hideAllFields, excludeFieldTypes, isPrepop, option ) { | |
mergeTags["pricing"].tags.push({ tag: '<?php echo self::$merge_tag; ?>', label: '<?php echo $label; ?>' }); | |
return mergeTags; | |
} | |
// hacky, but only temporary | |
jQuery(document).ready(function($){ | |
var calcMergeTagSelect = $('#field_calculation_formula_variable_select'); | |
calcMergeTagSelect.find('optgroup').eq(0).append( '<option value="<?php echo self::$merge_tag; ?>"><?php echo $label; ?></option>' ); | |
}); | |
</script> | |
<?php | |
//return the form object from the php hook | |
return $form; | |
} | |
static function has_subtotal_merge_tag( $field ) { | |
// check if form is passed | |
if( isset( $field['fields'] ) && is_array( $field['fields'] ) ) { | |
$form = $field; | |
foreach( $form['fields'] as $field ) { | |
if( self::has_subtotal_merge_tag( $field ) ) | |
return true; | |
} | |
} else { | |
if( isset( $field['calculationFormula'] ) && strpos( $field['calculationFormula'], self::$merge_tag ) !== false ) | |
return true; | |
} | |
return false; | |
} | |
} | |
new GWCalcSubtotal(); |
Currently, there is no easy way to get the current total (let’s call it the subtotal) of the form for use in calculations. It’s possible but you’ll have to enter all of your product merge tags into a long and complicated formula to get the subtotal.
This snippet helps you avoid that hassle by providing a {subtotal}
merge tag for use in your Gravity Form calculations.
{subtotal}
merge tag is only available in fields that support calculations.How do I install this snippet?
Easy peasy. Just copy and paste the code above into your theme's functions.php file.
How do I use this functionality?
This snippet will add a new “Subtotal” merge tag to the merge tag select available for the “Formula” setting on Calculation fields. Selecting this option will insert the {subtotal}
merge tag into your “Formula” setting. You can then use all available mathematical operations available to this field to manipulate this subtotal as needed.


Did this resource help you do something awesome with Gravity Forms? Then you'll absolutely love Gravity Perks; a suite of 32+ essential add-ons for Gravity Forms with support you can count on.
Thanks for this,
i used a multisite form with different products + options and amounts and need the following calculation :
Form page 01 with Product #1: Internet Flatrate (yes/no) + 25$ per month if yes –> show field »Private IP4 Adress (yes/no)« + 5$ per month if yes –> show field »Amount« (1-10) Subtotal = Price per Month (product01 + (option*amount))
Form page 02 with Product #2: Voice-over-IP (yes/no) + 15$ per month} if yes –> show field »Additional phone numbers (yes/no)« + 5$ per month} if yes –> show field »Amount« (1-10)} Subtotal = Price per Month (product 01 + (product 02 + (option*amount)))
Here is a small example: Internet Flat 25$ + 3xIP4(5$ per IP) – 40$ per month
Total: 95$ per month
Any ideas how I can achieve this?
Thanks for your help.
Hey Robby, To ensure that all calculations go through properly, your best bet may be the dedicated Gravity Forms eCommerce Fields perk we offer. All of the calculations can be handled with Gravity Forms Product plus options. Then to ensure the correct fields show you can use conditional logic. IF you have a Gravity Perks License we would be more than happy to take a look at the form. Just drop us a line through our support page. 😃
Thank you for this! It’s really helped.
I get a strange error though when I view an entry . Cannot modify header information – headers already sent by (output started at /home/****/public_html/****/wp-content/plugins/code-snippets/php/snippet-ops.php(446) : eval()’d code:222) in /home/*****/public_html/*****/wp-admin/admin-header.php on line 9
It’s coming from this portion: function add_merge_tags( $form ) {
<
script>
it only shows when I view an entry. I’ve checked for extra lines and deleted the space after the ?> but it’s still there.
It’s not affecting the site at all – just wondering if I should be looking into it further?
Hello Alissa, this is a bit of a strange one. Have you tried running a conflict test or ran some Snippet Troubleshooting to make sure nothing else was interfering with the code? IF you have a Gravity Wiz license we could take a closer look into this for you. You could reach out to us through our support page found here.
Does this plugin include calculating flat rate tax, for total purchase on the site?
Hello Anthony, This snippet would allow for the Subtotal Merge tag to be displayed and used within calculations. So you could set up a calculation field that uses the subtotal and calculates how much the tax should be that can later be used within the total, you can then name this tax to display how much they are being charged. Our Gravity Forms eCommerce Fields plugin already has a tax field pre-built within it to make it easier for you.
Thank you so much! This is epic for long forms. I wasn’t able to exclude tax from a “tip” field, but that’s okay! If anyone has a hint for me there, it’s appreciated. Thanks again for this solution!
Hello Sarah, how are you calculating the tax field currently? Let us know. 😃
Hi and thanks! A product field called “tax” (quantity field disabled) with the calculation: {subtotal} * .082
Here’s the working form in case it helps anyone else, too. It’s as simple as can be, for a temporary solution. They are a local food truck trying to keep some business going during the pandemic. foodlishus.com/order/
Hello Sarah, Sadly the subtotal field will take in all products. The only way around this would be to get the Gravity Forms eCommerce Fields perk. This will allow you to add a tax field as well as exclude products from the tax field.
Hello!
When I edit the single form entry in the admin side all the fields where the subtotal is used turn into zero values. Seems to be a bug or am I missing something here?
Thanks!
Hello Suusa, how are you currently using the subtotal field? Is it calculating numbers, products or what? Do you have a public site where we can see this information? Thank you so much!
Thanks for the fast replay. Yes, I’m using number field to calculate tax and show total on some products. Can’t give url at the moment but heres a screen: http://tiny.cc/5ukymz
Hello Suusa, I have just tested this out and everything seems to be working correctly. Are you using products to calculate the subtotal? When used with products the subtotal should calculate. Could you give that a try? 😀
Thanks for this,
trying to achieve the following:
Calculation: {subtotal} *0.15. (Add tax to product price). – WORKS PERFECT
Calculation 2: {subtotal} *0.025 (Add credit card fee). – HAVING PROBLEMS
TOTAL PRICE:
Problem is ‘calculation 2’ changes the subtotal which then makes it incorrect for calculation 1.
Any ideas how I can achieve this?
Thanks for your help.
Hey Michael, Looks like you are running into an issue with using two subtotal merge tags. Currently what is happening is the first calculation is running then replacing the subtotal with the new calculated subtotal. When you get to the next calculation it will now use the new subtotal in this calculation. You can accomplish this the easy way by getting Gravity Forms eCommerce Fields or you could actually reserve a subtotal field with just the {subtotal} merge tag, then use that fields price to create a new field with calculations that uses the new subtotal fields price merge tag ({Subtotal (Price):3.2}) to calculate the tax and fee. If you are still having issues after using the modifier this way, could you please drop us a support request. :)
I’m not having much luck getting this to work. I have a multi-page form with products on a few pages but the total for my calculation field is zero.
never mind. It was a formula error. Thanks for always being so awesome. Love you’re site and your code snippets.
Hello Dave,
Happy that you were able to get the calculation on your total form to work. Have a great day! :)
Can I able to use IF ELSE condition in merge tag calculation .please help me how we can do this. I am doing like below but it is not working for me. if($ 1-Year:90:48.88) 58.56 else 4.88
Gravity Forms doesn’t support if/else conditions in merge tags, but it does support conditional logic for number field. You could add conditional logic to a Product field and show/hide it based on the results of a calculation in a hidden number field.
You are great person, Thank you so much
❤️