Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save adpeate/252131abd3b20e2c721778580c227aa5 to your computer and use it in GitHub Desktop.

Select an option

Save adpeate/252131abd3b20e2c721778580c227aa5 to your computer and use it in GitHub Desktop.
Gravity Wiz // Gravity Forms // AJAX Popluation
<?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