Exclude Products from Coupon Discount

Exclude specific products when calculating discounts with the Gravity Forms Coupons add-on.

Requires Gravity Forms Coupons v1.1

Code

Filename: gw-coupons-exclude-products.php

<?php
/**
 * Gravity Wiz // Gravity Forms Coupons // Exclude Products from Coupon Discount
 *
 * Exclude specific products when calculating discounts with the Gravity Forms Coupons add-on.
 *
 * Requires Gravity Forms Coupons v1.1
 *
 * @version 1.2.1
 * @author  David Smith <david@gravitywiz.com>
 * @license GPL-2.0+
 * @link    https://gravitywiz.com/...
 */
class GW_Coupons_Exclude_Products {

	protected static $is_script_output = false;
	public static $excluded_total      = null;

	public $_args = array();

	public function __construct( $args ) {

		// set our default arguments, parse against the provided arguments, and store for use throughout the class
		$this->_args = wp_parse_args( $args, array(
			'form_id'        => false,
			'exclude_fields' => array(),
		) );

		// do version check in the init to make sure if GF is going to be loaded, it is already loaded
		add_action( 'init', array( $this, 'init' ) );

	}

	function init() {

		$has_gravity_forms = property_exists( 'GFCommon', 'version' ) && version_compare( GFCommon::$version, '1.8', '>=' );
		$has_gf_coupons    = class_exists( 'GFCoupons' );

		// make sure we're running the required minimum version of Gravity Forms and GF Coupons
		if ( ! $has_gravity_forms || ! $has_gf_coupons ) {
			return;
		}

		// render
		add_filter( 'gform_pre_render', array( $this, 'load_form_script' ) );
		add_filter( 'gform_register_init_scripts', array( $this, 'add_init_script' ) );

		// submission
		add_action( 'gform_product_info', array( $this, 'stash_excluded_total' ), 4 /* Coupons run on 5 */, 2 );
		add_filter( 'gform_coupons_discount_amount', array( $this, 'modify_coupon_discount_amount' ), 10, 3 );

	}

	function load_form_script( $form ) {

		if ( $this->is_applicable_form( $form ) && ! self::$is_script_output ) {
			$this->output_script();
		}

		return $form;
	}

	function output_script() {
		?>

		<script type="text/javascript">

			( function( $ ) {

				if( window.gform ) {

					gform.addFilter( 'gform_coupons_discount_amount', function( discount, couponType, couponAmount, price, totalDiscount ) {

						// pretty hacky... work our way up the chain to see if the 4th func up is the expected func
						var caller = arguments.callee.caller.caller.caller.caller;

						if( caller.name != 'PopulateDiscountInfo' ) {
							return discount;
						}

						var formId = caller.arguments[1],
							price  = price - getExcludedAmount( formId );

						if( couponType == 'percentage' ) {
							discount = price * Number( ( couponAmount / 100 ) );
						} else if( couponType == 'flat' ) {
							discount = Number( couponAmount );
							if( discount > price ) {
								discount = price;
							}
						}

						if( ! window.onTimeout && window.applyingCoupon ) {

							window.onTimeout = setTimeout( function() {

								window.onTimeout = false;
								window.applyingCoupon = false;

								$( document ).trigger( 'gform_post_conditional_logic' );

							}, 1 );

						}

						return discount;
					}, 15 );

				}

				function getExcludedAmount( formId ) {

					var excludeFields = gf_global.gfcep[ formId ],
						amount        = 0;

					if( ! excludeFields ) {
						return 0;
					}

					for( var i = 0; i < excludeFields.length; i++ ) {
						var productAmount = gformCalculateProductPrice( formId, excludeFields[ i ] );
						amount += productAmount;
					}

					return amount;
				}

			} )( jQuery );

		</script>

		<?php

		self::$is_script_output = true;

	}

	function add_init_script( $form ) {

		if ( ! $this->is_applicable_form( $form ) ) {
			return;
		}

		$exclude_fields_json = json_encode( $this->_args['exclude_fields'] );

		$script = "if( typeof gf_global != 'undefined' ) {
			if( typeof gf_global.gwcep == 'undefined' ) {
				gf_global.gfcep = [];
			}
			gf_global.gfcep[ {$this->_args['form_id']} ] = {$exclude_fields_json};
		}";

		GFFormDisplay::add_init_script( $this->_args['form_id'], 'gfcep', GFFormDisplay::ON_PAGE_RENDER, $script );

	}

	function stash_excluded_total( $product_data, $form ) {

		if ( ! $this->is_applicable_form( $form ) ) {
			return $product_data;
		}

		self::$excluded_total = 0;

		foreach ( $product_data['products'] as $field_id => $data ) {
			if ( in_array( $field_id, $this->_args['exclude_fields'] ) ) {
				self::$excluded_total += GFCommon::to_number( $data['price'] );
			}
		}

		return $product_data;
	}

	function modify_coupon_discount_amount( $discount, $coupon, $price ) {

		if ( ! self::$excluded_total ) {
			return $discount;
		}

		$price    = $price - self::$excluded_total;
		$currency = new RGCurrency( GFCommon::get_currency() );
		$amount   = $currency->to_number( $coupon['amount'] );

		if ( $coupon['type'] == 'percentage' ) {
			$discount = $price * ( $amount / 100 );
		} elseif ( $coupon['type'] == 'flat' ) {
			$discount = $amount;
			if ( $discount > $price ) {
				$discount = $price;
			}
		}

		return $discount;
	}

	function is_applicable_form( $form ) {

		$coupon_fields         = GFCommon::get_fields_by_type( $form, array( 'coupon' ) );
		$is_applicable_form_id = $form['id'] == $this->_args['form_id'];

		return $is_applicable_form_id && ! empty( $coupon_fields );
	}

}

# Configuration

new GW_Coupons_Exclude_Products( array(
	'form_id'        => 123,
	'exclude_fields' => array( 4, 5 ),
) );

Leave a Reply

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

  • Trouble installing this snippet? See our troubleshooting tips.
  • Need to include code? Create a gist and link to it in your comment.
  • Reporting a bug? Provide a URL where this issue can be recreated.

By commenting, I understand that I may receive emails related to Gravity Wiz and can unsubscribe at any time.