Forked from spivurno/gw-gravity-forms-ajax-population.php
Last active
April 28, 2017 09:39
-
-
Save adpeate/252131abd3b20e2c721778580c227aa5 to your computer and use it in GitHub Desktop.
Gravity Wiz // Gravity Forms // AJAX Popluation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Gravity Wiz // Gravity Forms // AJAX Population | |
| * | |
| * Populate one or many fields from a remote data source (only .csv files are currently supported) based on the selected value of a field on the form. | |
| * | |
| * Example: You have multiple brands of lumber. The lumber comes in different sizes. You can store each lumber brand and its corresponding length, width, and height in a spreadsheet (csv format) and then populate this data into separate length, width and height fields on the form when a lumber brand is selectd from a drop down field on the form. | |
| * | |
| * @version 1.2 | |
| * @author David Smith <david@gravitywiz.com>. Modified by Alan Peate <alan@magerage.co.uk> | |
| * @license GPL-2.0+ | |
| * @link http://gravitywiz.com/ | |
| * | |
| * This version has been modified to work for logged out users. | |
| * It has been improved to support resetting fields on change, targeting specific fields next, targeting specific columns etc | |
| * It more cleanly resets and improves the visual behaviour of fields on load and change etc. | |
| * | |
| */ | |
| class GW_AJAX_Population { | |
| protected static $is_script_output = false; | |
| public function __construct( $args = array() ) { | |
| // 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, | |
| 'target_form_id' => false, | |
| 'trigger_field_id' => false, | |
| 'target_field_id' => false, | |
| 'target_column' => false, | |
| 'data_map' => array() | |
| ) ); | |
| // map synonyms | |
| if( $this->_args['target_form_id'] ) { | |
| $this->_args['form_id'] = $this->_args['target_form_id']; | |
| } | |
| // 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() { | |
| // make sure we're running the required minimum version of Gravity Forms | |
| if( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) ) { | |
| return; | |
| } | |
| // time for hooks | |
| add_filter( 'gform_pre_render', array( $this, 'load_form_script' ) ); | |
| add_filter( 'gform_register_init_scripts', array( $this, 'add_init_script' ) ); | |
| add_action( 'wp_ajax_gwap_request_data', array( $this, 'ajax_request_data' ) ); | |
| add_action( 'wp_ajax_nopriv_gwap_request_data', array( $this, 'ajax_request_data' ) ); | |
| if(isset($_REQUEST['action'])){ | |
| do_action( 'wp_ajax_gwap_request_data'); | |
| do_action( 'wp_ajax_nopriv_gwap_request_data'); | |
| } | |
| } | |
| 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( $ ) { | |
| window.GWAJAXPop = function( args ) { | |
| var self = this; | |
| // copy all args to current object: (list expected props) | |
| for( prop in args ) { | |
| if( args.hasOwnProperty( prop ) ) | |
| self[prop] = args[prop]; | |
| } | |
| self.init = function() { | |
| $triggerField = $( '#input_' + self.formId + '_' + self.triggerFieldId ); | |
| self.reset(); | |
| $triggerField.change( function() { | |
| self.reset(); | |
| var value = $( this ).val(); | |
| if( ! value ) { | |
| return; | |
| } | |
| $.post( self.ajaxUrl, { | |
| action: 'gwap_request_data', | |
| form_id: self.formId, | |
| trigger_field_id: self.triggerFieldId, | |
| trigger_value: $( this ).val(), | |
| form_data: $('#gform_'+self.formId).serialize() | |
| }, function( response ) { | |
| response = $.parseJSON( response ); | |
| if( response.is_error ) { | |
| self.reset(); | |
| } else { | |
| var mapping = response.data; | |
| self.populateValues( mapping ); | |
| } | |
| } ); | |
| } ); | |
| $triggerField.trigger('change'); | |
| }; | |
| self.reset = function() { | |
| $.each( self.resetFields, function( index, fieldId ) { | |
| $( '#input_' + self.formId + '_' + fieldId ).find('option').remove(); | |
| $( '#input_' + self.formId + '_' + fieldId ).val(''); | |
| } ); | |
| } | |
| self.populateValues = function( values ) { | |
| $( '#input_' + self.formId + '_' + self.targetFieldId ).append('<option value="">Please Select</option>'); | |
| $.each( values, function( index, value ) { | |
| $( '#input_' + self.formId + '_' + self.targetFieldId ).append('<option value="' + value + '">' + value + '</option>'); | |
| } ); | |
| }; | |
| self.getEmptyMapping = function() { | |
| var mapping = {}; | |
| $.each( self.dataMap, function( column, fieldId ) { | |
| mapping[ fieldId ] = ''; | |
| } ); | |
| return mapping; | |
| }; | |
| self.init(); | |
| } | |
| } )( jQuery ); | |
| </script> | |
| <?php | |
| self::$is_script_output = true; | |
| } | |
| function add_init_script( $form ) { | |
| if( ! $this->is_applicable_form( $form ) ) { | |
| return; | |
| } | |
| $args = array( | |
| 'formId' => $this->_args['form_id'], | |
| 'triggerFieldId' => $this->_args['trigger_field_id'], | |
| 'targetFieldId' => $this->_args['target_field_id'], | |
| 'dataMap' => $this->_args['data_map'], | |
| 'resetFields' => $this->_args['reset_fields'], | |
| 'ajaxUrl' => admin_url( 'admin-ajax.php' ) | |
| ); | |
| $script = 'new GWAJAXPop( ' . json_encode( $args ) . ' );'; | |
| $slug = implode( '_', array( 'gw_ajax_pop', $this->_args['form_id'], $this->_args['trigger_field_id'] ) ); | |
| GFFormDisplay::add_init_script( $this->_args['form_id'], $slug, GFFormDisplay::ON_PAGE_RENDER, $script ); | |
| } | |
| function ajax_request_data() { | |
| $form_id = rgpost( 'form_id' ); | |
| $trigger_field_id = rgpost( 'trigger_field_id' ); | |
| if( $form_id != $this->_args['form_id'] || $trigger_field_id != $this->_args['trigger_field_id'] ) { | |
| return; | |
| } | |
| $trigger_value = rgpost( 'trigger_value' ); | |
| $data = $this->get_data( $trigger_value ); | |
| $response = array(); | |
| if( empty( $data ) ) { | |
| $response['is_error'] = true; | |
| $response['message'] = __( 'No data found.' ); | |
| } else { | |
| $response['is_error'] = false; | |
| $response['data'] = $data; | |
| } | |
| die( json_encode( $response ) ); | |
| } | |
| function get_data( $source_value ) { | |
| $trigger_field_id = rgpost( 'trigger_field_id' ); | |
| if( is_callable( $this->_args['ajax_callback'] ) ) { | |
| $data = call_user_func( $this->_args['ajax_callback'], $source_value, $this ); | |
| } else if( $this->_args['file'] ) { | |
| $file_data = $this->get_data_from_file( $this->_args['file'] ); | |
| $data = $this->get_rows_by_value( trim($source_value), trim(array_search( $trigger_field_id, $this->_args['data_map'] )), $file_data ); | |
| } | |
| return $data; | |
| } | |
| function get_data_from_file( $file ) { | |
| $data = array(); | |
| $contents = file_get_contents( $file ); | |
| $lines = strpos( $contents, "\n" ) ? explode( "\n", $contents ) : explode( "\r", $contents ); | |
| foreach( $lines as $line ) { | |
| $bits = explode( ',', $line ); | |
| $row = array(); | |
| foreach( $bits as $index => $bit ) { | |
| $row[ $this->digits_to_letters( $index ) ] = trim($bit); | |
| } | |
| $data[] = $row; | |
| } | |
| return $data; | |
| } | |
| function get_rows_by_value( $value, $column, $data ) { | |
| $formData = array(); | |
| parse_str(rgpost('form_data'), $formData); | |
| $params = array(); | |
| foreach($formData as $key => $val){ | |
| foreach($this->_args['data_map'] as $c => $i){ | |
| if($key == "input_{$i}"){ | |
| if($val){ | |
| $params[$c] = $val; | |
| } | |
| } | |
| } | |
| } | |
| $return = array(); | |
| foreach( $data as $row ) { | |
| $break = false; | |
| foreach($params as $c => $val){ | |
| if($row[$c] != $val){ | |
| $break = true; | |
| } | |
| } | |
| if($break){ | |
| continue; | |
| } | |
| if( $row[$column] == $value ) { | |
| if(!in_array($row[$this->_args['target_column']], $return)){ | |
| $return[] = $row[$this->_args['target_column']]; | |
| } | |
| } | |
| } | |
| return $return; | |
| } | |
| function get_row_by_value( $value, $column, $data ) { | |
| foreach( $data as $row ) { | |
| if( $row[ $column ] == $value ) { | |
| return $row; | |
| } | |
| } | |
| return false; | |
| } | |
| function sub_columns_for_field_ids( $row ) { | |
| $_row = array(); | |
| foreach( $row as $column => $value ) { | |
| $_row[ $this->sub_column_for_field_id( $column ) ] = trim($value); | |
| } | |
| return $_row; | |
| } | |
| function sub_column_for_field_id( $column ) { | |
| $field_id = rgar( $this->_args['data_map'], $column ); | |
| return $field_id ? $field_id : $column; | |
| } | |
| function digits_to_letters( $input ) { | |
| return strtr( $input, '0123456789', 'ABCDEFGHIJ' ); | |
| } | |
| function is_applicable_form( $form ) { | |
| $form_id = isset( $form['id'] ) ? $form['id'] : $form; | |
| return $form_id == $this->_args['form_id']; | |
| } | |
| } | |
| //Configuration examples: | |
| //Let's assume we have 3 dropdowns. We need to trigger actions on dropdowns 1 and 2 in order to populate dropdowns 2 and 3 respectively. | |
| $dataMap = array( | |
| 'A' => 1, | |
| 'B' => 2, | |
| 'C' => 3 | |
| ); | |
| $filterFile = ABSPATH . '/wp-content/uploads/filters.csv'; | |
| //dropdown 1 | |
| new GW_AJAX_Population( array( | |
| 'form_id' => 40, //gravity form ID - fairly obvious | |
| 'trigger_field_id' => 1, //field ID for the dropdown that will trigger population | |
| 'target_field_id' => 2, //field ID for the next dropdown to populate | |
| 'target_column' => 'B', //column header in the CSV for the next dropdown to populate | |
| //an array of CSV column names and their corresponding field IDs (from the form) | |
| //this is needed to validate field data | |
| 'data_map' => $dataMap, | |
| //field IDs to reset upon change or init. These should be the IDs of every dropdown after this dropdown | |
| 'reset_fields' => array( | |
| 2, | |
| 3 | |
| ), | |
| 'file' => $filterFile, | |
| ) ); | |
| //dropdown 2 - follow the logic above | |
| new GW_AJAX_Population( array( | |
| 'form_id' => 40, | |
| 'trigger_field_id' => 2, | |
| 'target_field_id' => 3, | |
| 'target_column' => 'C', | |
| // an array of CSV column names and their corresponding field IDs (from the form) | |
| 'data_map' => $dataMap, | |
| 'reset_fields' => array( | |
| 3 | |
| ), | |
| 'file' => $filterFile, | |
| ) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment