spivurno
9/24/2013 - 2:03 PM

GW User Progress // Store WP user form progress as they fill out the form. Currently limited to checkboxes.

GW User Progress // Store WP user form progress as they fill out the form. Currently limited to checkboxes.

<?php
/**
* GW User Progress
* 
* Store WP user form progress as they fill out the form. Currently limited to checkboxes.
* 
*/
class GWUserProgress {
    
    private $_args;
    private static $_is_script_output;
    
    public static $user_progress_key = 'gwup_user_progress';
    
    public function __construct() {
        
        add_action( 'gform_field_advanced_settings', array( $this, 'field_settings_ui' ), 10, 2 );
        add_action( 'gform_editor_js', array( $this, 'field_settings_js' ) );
        
        if( ! is_user_logged_in() )
            return;
        
        add_filter( 'gform_pre_render', array( $this, 'pre_render' ) );
        add_action( 'wp_ajax_gwup_update_user_progress', array( $this, 'ajax_update_user_progress' ) );
        add_action( 'wp_ajax_nopriv_gwup_update_user_progress', array( $this, 'ajax_update_user_progress' ) );
        
    }

    public function field_settings_ui( $position ) {
        
        if( $position != 450 )
            return;
        
        ?>

        <li class="gwup-enable-setting field_setting">
            <input type="checkbox" id="gwup-enable" value="1" onclick="SetFieldProperty( 'gwupEnable', this.checked )">
            <label class="inline" for="gwup-enable">
                <?php _e( 'Enable User Progress Tracking' ); ?>
            </label>
        </li>

        <?php
    }

    public function field_settings_js() {
        ?>

        <script type="text/javascript">
            (function($) {

                $(document).bind('gform_load_field_settings', function(event, field, form) {
                    $("#gwup-enable").attr( 'checked', field.gwupEnable == true );
                });
                
                fieldSettings['checkbox'] += ', .gwup-enable-setting';

            })(jQuery);
        </script>

        <?php
    }
    
    public function pre_render( $form ) {
        
        if( ! self::has_user_progress_enabled( $form ) )
            return $form;
        
        add_filter( 'gform_register_init_scripts', array( $this, 'register_init_script' ) );
        
        $user_id = get_current_user_id();
        
        foreach( $form['fields'] as &$field ) {
            
            if( ! rgar( $field, 'gwupEnable' ) )
                continue;
            
            if( ! empty( $field['inputs'] ) ) {
                foreach( $field['inputs'] as $index => &$input ) {
                    if( self::get_user_progress( $user_id, $form['id'], $input['id'] ) )
                        $field['choices'][$index]['isSelected'] = true;
                }
            } else {
                // @TODO: add support for other field types
            }
            
        }
        
        if( ! self::$_is_script_output )
            $this->output_script();
        
        return $form;
    }
    
    public function output_script() {
        ?>
        
        <script type="text/javascript">
            
            var gwup = {};
            
            (function($){
                
                window.gwup = function( args ) {
                    
                    this.formId   = args.formId;
                    this.inputIds = args.inputIds;
                    this.ajaxUrl  = args.ajaxUrl;
                    this.userId   = args.userId;
                    this.nonce    = args.nonce;
                    
                    this.init = function() {
                        
                        var gwup = this;
                        
                        for( i in this.inputIds ) {
                            
                            var inputId     = String( this.inputIds[i] ),
                                inputIdBits = inputId.split('.'),
                                inputHtmlId = '';
                            
                            if( inputIdBits.length > 1 ) {
                                inputHtmlId = '#choice_' + inputIdBits[0] + '_' + inputIdBits[1];
                            } else {
                                // @TODO: untested...
                                inputHtmlId = '#input_' + this.formId + '_' + inputId;
                            }
                            
                            $(inputHtmlId).data( 'inputId', inputId );
                            
                            // @TODO: 'click' only supports checkboxes
                            $(document).on( 'click', inputHtmlId, function(){
                                
                                var spinner = gwup.ajaxSpinner( $(this), gf_global.base_url + '/images/spinner.gif', 'border: 0 none !important;border-radius: 0 0 0 0;box-shadow: 0 0 0 0;float: left;margin: 2px 0 0 2px;' ),
                                    elem    = $(this);
                                
                                elem.hide();
                                
                                $.post( gwup.ajaxUrl, {
                                    user_id:  gwup.userId,
                                    form_id:  gwup.formId,
                                    input_id: $(this).data( 'inputId' ),
                                    value:    $(this).is(':checked') ? 1 : 0, // @TODO: only supports checkboxes
                                    action:   'gwup_update_user_progress',
                                    nonce:    gwup.nonce
                                }, function( response ) {
                                    spinner.destroy();
                                    elem.show();
                                } );
                            });
                            
                        }
                        
                    }
                    
                    this.ajaxSpinner = function(elem, imageSrc, inlineStyles) {

                        var imageSrc = typeof imageSrc == 'undefined' ? '/images/ajax-loader.gif': imageSrc;
                        var inlineStyles = typeof inlineStyles != 'undefined' ? inlineStyles : '';

                        this.elem = elem;
                        this.image = '<img class="gfspinner" src="' + imageSrc + '" style="' + inlineStyles + '" />';

                        this.init = function() {
                            this.spinner = jQuery(this.image);
                            jQuery(this.elem).after(this.spinner);
                            return this;
                        }

                        this.destroy = function() {
                            jQuery(this.spinner).remove();
                        }

                        return this.init();
                    }
                    
                    this.init();
                    
                }
                
            })(jQuery);
            
        </script>
        
        <?php
        
        self::$_is_script_output = true;
        
    }
    
    public function register_init_script( $form ) {
        
        // remove this function from the filter otherwise it will be called for every other form on the page
        remove_filter( 'gform_register_init_scripts', array( $this, 'register_init_script' ) );
        
        $args = array(
            'formId'   => $form['id'],
            'inputIds' => self::get_input_ids( $form ),
            'ajaxUrl'  => admin_url( 'admin-ajax.php' ),
            'userId'   => get_current_user_id(),
            'nonce'    => wp_create_nonce( 'gwup_update_user_progress' )
            );
        
        $script = "new gwup(" . json_encode( $args ) . ");";
        GFFormDisplay::add_init_script( $form['id'], 'gwup_' . $this->_args['form_id'], GFFormDisplay::ON_PAGE_RENDER, $script );
        
    }
    
    public function ajax_update_user_progress() {
        
        $user_id = rgpost( 'user_id' );
        $form_id = rgpost( 'form_id' );
        $input_id = rgpost( 'input_id' );
        $value = rgpost( 'value' );
        
        if( ! wp_verify_nonce( rgpost( 'nonce' ), 'gwup_update_user_progress' ) || get_current_user_id() != $user_id )
            die();
        
        die( self::update_user_progress( $user_id, $form_id, $input_id, $value ) );
    }
    
    public static function has_user_progress_enabled( $form ) {
        foreach( $form['fields'] as $field ) {
            if( rgar( $field, 'gwupEnable' ) )
                return true;
        }
        return false;
    }
    
    public static function get_user_progress( $user_id, $form_id = false, $input_id = false ) {
        
        $cache_key = self::$user_progress_key . '-' . $user_id;
        
        $user_progress = wp_cache_get( $cache_key, 'gwup' );
        if( empty( $user_progress ) ) {
            $user_progress = get_user_meta( $user_id, self::$user_progress_key, true );
            wp_cache_set( $cache_key, $user_progress, 'gwup' );
        }
                
        if( $input_id ) {
            $user_progress = rgars( $user_progress, "{$form_id}/{$input_id}" );
        } else if( $form_id ) {
            $user_progress = rgar( $user_progress, $form_id );
        }
        
        return $user_progress;
    }
    
    public static function update_user_progress( $user_id, $form_id, $input_id, $value ) {
        
        $user_progress = self::get_user_progress( $user_id );
        
        if( ! is_array( $user_progress ) )
            $user_progress = array();
        
        if( ! isset( $user_progress[$form_id] ) )
            $user_progress[$form_id] = array();
        
        $user_progress[$form_id][$input_id] = $value;
        $result = update_user_meta( $user_id, self::$user_progress_key, $user_progress );
        
        return $result;
    }
    
    public static function get_input_ids( $form ) {
            
        $input_ids = array();
        
        foreach( $form['fields'] as $field ) {
            
            if( ! rgar( $field, 'gwupEnable' ) )
                continue;
            
            if( ! empty( $field['inputs'] ) ) {
                foreach( $field['inputs'] as $input ) {
                    $input_ids[] = $input['id'];
                }
            } else {
                $input_ids[] = $field['id'];
            }
            
        }
        
        return $input_ids;
    }
    
}

new GWUserProgress();