Last active
October 20, 2021 10:19
-
-
Save spivurno/c3526301a97a8ea26570 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.1 | |
* @author David Smith <[email protected]> | |
* @license GPL-2.0+ | |
* @link http://gravitywiz.com/... | |
*/ | |
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, | |
'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' ) ); | |
} | |
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 ); | |
$triggerField.change( function() { | |
var value = $( this ).val(); | |
if( ! value ) { | |
self.populateValues( self.getEmptyMapping() ); | |
return; | |
} | |
$.post( self.ajaxUrl, { | |
action: 'gwap_request_data', | |
form_id: self.formId, | |
trigger_field_id: self.triggerFieldId, | |
trigger_value: $( this ).val() | |
}, function( response ) { | |
response = $.parseJSON( response ); | |
if( response.is_error ) { | |
self.populateValues( self.getEmptyMapping() ); | |
} else { | |
var mapping = response.data; | |
self.populateValues( mapping ); | |
} | |
} ); | |
} ); | |
}; | |
self.populateValues = function( values ) { | |
$.each( values, function( fieldId, value ) { | |
$( '#input_' + self.formId + '_' + fieldId ).val( value ); | |
} ); | |
}; | |
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'], | |
'dataMap' => $this->_args['data_map'], | |
'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 ) { | |
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( $source_value ); | |
$data = $this->sub_columns_for_field_ids( $this->get_row_by_value( $source_value, 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 ) ] = $bit; | |
} | |
$data[] = $row; | |
} | |
return $data; | |
} | |
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 ) ] = $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 | |
$tt_ajax_pop = new GW_AJAX_Population( array( | |
'source_form_id' => 1108, // form on which the unique ID was generated | |
'source_field_id' => 15, // the field ID of the unique ID | |
'target_form_id' => 1109, // the form that data will be populated into | |
'trigger_field_id' => 9, // the field that the unique ID will be entered into and trigger the population | |
'data_map' => array( // a map of field IDs from the source form that should be mapped into field IDs on the target form | |
11 => 10 // 11 = source form field ID, 10 = target form field ID | |
), | |
'ajax_callback' => function( $source_value, $ajax_pop_obj ) { | |
$entries = GFAPI::get_entries( $ajax_pop_obj->_args['source_form_id'], array( | |
'field_filters' => array( | |
array( | |
'key' => $ajax_pop_obj->_args['source_field_id'], | |
'value' => $source_value | |
) | |
) | |
) ); | |
if( empty( $entries ) ) { | |
$entry = array(); | |
} else { | |
$entry = array_shift( $entries ); | |
} | |
$data = array(); | |
foreach( $ajax_pop_obj->_args['data_map'] as $source_field_id => $target_field_id ) { | |
$data[ $target_field_id ] = rgar( $entry, $source_field_id ); | |
} | |
return $data; | |
} | |
) ); | |
new GW_AJAX_Population( array( | |
'form_id' => 636, | |
'trigger_field_id' => 99, | |
// an array of CSV column names and their corresponding field IDs (from the form) | |
'data_map' => array( | |
'A' => 99, | |
'B' => 147, | |
'C' => 148 | |
), | |
'file' => ABSPATH . '/wp-content/uploads/Accent Band Sheet.csv' | |
) ); | |
new GW_AJAX_Population( array( | |
'form_id' => 636, | |
'trigger_field_id' => 100, | |
// an array of CSV column names and their corresponding field IDs (from the form) | |
'data_map' => array( | |
'A' => 100, | |
'B' => 149, | |
'C' => 150 | |
), | |
'file' => ABSPATH . '/wp-content/uploads/Accent Band Sheet.csv' | |
) ); | |
new GW_AJAX_Population( array( | |
'form_id' => 636, | |
'trigger_field_id' => 101, | |
'data_map' => array( | |
'A' => 101, | |
'B' => 152, | |
'C' => 151 | |
), | |
'file' => ABSPATH . '/wp-content/uploads/Accent Band Sheet.csv' | |
) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for all these great tools you share with the community. Very generous and appreciated.
I have tried implementing this one without success. My path to CSV is correct, and I believe I have configured the array and csv correctly. Here is my approach, using your lumber example:
Form ID is 20 (and the form has Ajax enabled and no re-captcha)
Field ID 1 has label "Lumber type" with two dropdown options: "Wide lumber" and "Square lumber"
Field ID 2 has label "Width"
Field ID 3 has label "Length"
When someone chooses a lumber type, it should populate the other two fields based on a CSV file which looks like this (I tried with and without the first line):
A,B,C
Wide lumber,10 inches,5 inches
Square lumber,10 inches,10 inches
I mapped this data as follows when instantiating your class:
When I load this form and make a selection from my dropdown menu, the other two fields don't change accordingly.
Any help you might provide would be greatly appreciated. Perhaps I am simply misunderstanding how it needs to be implemented.
Thanks very much.