spivurno of Gravity Wiz
4/29/2014 - 2:58 PM

Gravity Wiz // First X Items Free

Gravity Wiz // First X Items Free

<?php
/**
* First X Items Free
*
* Discounts the first X number of items as free.
*
* @author    David Smith <david@gravitywiz.com>
* @license   GPL-2.0+
* @link      http://gravitywiz.com/...
* @copyright 2013 Gravity Wiz
*/
class GWFirstXFree {

    private $_args;
    private static $_is_script_output;

    public function __construct( $args ) {

        $this->_args = wp_parse_args( $args, array(
            'form_id' => false,
            'field_ids' => array(),
            'number_free' => 1,
            'discount_label' => __( 'First %d Items Free Discount' )
        ) );

        extract( $this->_args ); // gives us $form_id, $field_ids, $number_free

        if( ! $form_id || empty( $field_ids ) )
            return;

        add_filter( 'gform_pre_render_' . $form_id, array( $this, 'pre_render' ) );
        add_filter( 'gform_register_init_scripts_' . $form_id, array( $this, 'register_init_script' ) );
        add_filter( 'gform_product_info_' . $form_id, array( $this, 'apply_discount' ), 10, 3 );

    }

    public function pre_render( $form ) {
        $this->output_script();
        return $form;
    }

    public function output_script() {

        if( self::$_is_script_output )
            return;

        ?>

        <script type="text/javascript">

            var gwfxf = {};

            ( function( $ ) {

                window.gwfxf = function( args ) {

                    this.init = function( args ) {

                        this.extractProperties( args );
                        var gwfxf = this;

                        gform.addFilter( 'gform_product_total', function( total ) {
                            return gwfxf.applyDiscount( total );
                        } );

                    }

                    this.applyDiscount = function( total ) {

                        var prices = [];

                        for( var i = 0; i < this.fieldIds.length; i++ ) {

                            var price = gformToNumber( $( '#ginput_base_price_' + this.formId + '_' + this.fieldIds[i] ).val() );
                            var qty = gformGetProductQuantity( this.formId, this.fieldIds[i] );

                            if( ! prices.length ) {

                                prices.push( { price: price, qty: qty } );

                            } else {

                                for( var j = 0; j < prices.length; j++ ) {
                                    if( price >= prices[j].price ) {
                                        prices.splice( j, 0, { price: price, qty: qty } );
                                        break;
                                    }
                                }

                            }

                        }

                        var numberFree = this.numberFree,
                            totalDiscount = 0;

                        for( var i = 0; i < prices.length; i++ ) {

                            var qty = prices[i].qty;

                            if( numberFree > qty ) {
                                numberFree -= qty;
                            } else {
                                qty = numberFree;
                                numberFree = 0;
                            }

                            totalDiscount += qty * prices[i].price;

                        }

                        return total - totalDiscount;
                    }

                    this.extractProperties = function( args ) {
                        // extract args as properties of this object
                        for( var prop in args ) {
                            if( args.hasOwnProperty( prop ) )
                                this[prop] = args[prop];
                        }
                    }

                    this.init( args );

                }

            })( jQuery );

        </script>

        <?php

        self::$_is_script_output = true;

    }

    public function register_init_script( $form ) {

        $args = array(
            'formId'   => $form['id'],
            'fieldIds' => $this->_args['field_ids'],
            'numberFree' => $this->_args['number_free']
        );

        $script = "new gwfxf(" . json_encode( $args ) . ");";
        $slug = 'gwfxf_' . $form['id'] . '_' . implode( '_', $this->_args['field_ids'] );

        GFFormDisplay::add_init_script( $form['id'], $slug, GFFormDisplay::ON_PAGE_RENDER, $script );

    }

    public function apply_discount( $product_info, $form, $lead ) {

        $total = GFCommon::get_total( $product_info );
        $disc_products = array();

        foreach( $product_info['products'] as $product_id => $product ) {

            if( ! in_array( $product_id, $this->_args['field_ids'] ) )
                continue;

            if( ! count( $disc_products ) ) {
                $disc_products[] = $product;
            } else {
                for( $i = 0; $i < count( $disc_products ); $i++ ) {
                    if( GFCommon::to_number( $product['price'] ) >= GFCommon::to_number( $disc_products[$i]['price'] ) ) {
                        array_splice( $disc_products, $i, 0, array( $product ) );
                        break;
                    }
                }
            }
        }

        $number_free = $this->_args['number_free'];
        $total_discount = 0;

        foreach( $disc_products as $disc_product ) {

            $qty = $disc_product['quantity'];
            $price = GFCommon::to_number( $disc_product['price'] );

            if( $number_free > $qty ) {
                $number_free -= $qty;
            } else {
                $qty = $number_free;
                $number_free = 0;
            }

            $total_discount += $qty * $price;

        }

        $product_info['products']['gwfxf_discount'] = array(
            'name' => sprintf( $this->_args['discount_label'], $this->_args['number_free'] ),
            'price' => GFCommon::to_money( $total_discount * -1 ),
            'quantity' => 1
        );

        return $product_info;
    }

}

new GWFirstXFree( array(
    'form_id' => 381,
    'field_ids' => array( 1, 2, 3, 4 ),
    'number_free' => 2
) );