Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save claygriffiths/d0a0e6119dc0dade9f40fb98157477bd to your computer and use it in GitHub Desktop.
Save claygriffiths/d0a0e6119dc0dade9f40fb98157477bd to your computer and use it in GitHub Desktop.
Gravity Perks // GP Limit Choices // Field Groups
<?php
/**
* Gravity Perks // GP Limit Choices // Field Group
*
* Specify a group of fields that should create a unique choice to limited. For example, a Date field and Radio Button field could be
* combined to sell x tickets per date where the ticket type is controlled by the Radio Button field and the date is
* selected in the Date field.
*
* @version 1.3
* @author David Smith <david@gravitywiz.com>
* @license GPL-2.0+
* @link http://gravitywiz.com/documentation/gp-limit-choices/
*
* Plugin Name: GP Limit Choices - Field Groups
* Plugin URI: http://gravitywiz.com/documentation/gp-limit-choices/
* Description: Specify a group of fields that should create a unique choice to be limited.
* Author: Gravity Wiz
* Version: 1.2
* Author URI: http://gravitywiz.com
*/
class GP_Limit_Choices_Field_Group {
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,
'field_ids' => array(),
) );
$this->_args['hash'] = hash_hmac( 'sha256', serialize( $this->_args ), 'gplc_field_group' );
add_filter( 'gwlc_choice_counts_query', array( $this, 'limit_by_field_group' ), 10, 2 );
add_action( 'wp_ajax_gplcfg_refresh_field', array( $this, 'ajax_refresh' ) );
add_action( 'wp_ajax_nopriv_gplcfg_refresh_field', array( $this, 'ajax_refresh' ) );
add_filter( 'gform_pre_render', array( $this, 'load_form_script' ), 10, 2 );
add_filter( 'gform_register_init_scripts', array( $this, 'add_init_script' ), 10, 2 );
if( rgpost( 'action' ) == 'gplcfg_refresh_field' ) {
remove_action( 'wp', array( 'GFForms', 'maybe_process_form' ), 9 );
remove_action( 'admin_init', array( 'GFForms', 'maybe_process_form' ), 9 );
}
}
public function limit_by_field_group( $query, $field ) {
global $wpdb;
$field_ids = $this->_args['field_ids'];
if( ! $this->is_applicable_form( $field->formId ) || ! in_array( $field->id, $field_ids ) ) {
return $query;
}
unset( $field_ids[ array_search( $field->id, $field_ids ) ] );
$field_ids = array_values( $field_ids );
$form = GFAPI::get_form( $field->formId );
$join = $where = array();
$select = $from = '';
foreach( $field_ids as $index => $field_id ) {
$field = GFFormsModel::get_field( $form, $field_id );
$alias = sprintf( 'fgem%d', $index + 1 );
$_alias = null;
if( $index == 0 ) {
$_alias = $alias;
$select = "SELECT DISTINCT {$alias}.entry_id";
$from = "FROM {$wpdb->prefix}gf_entry_meta {$alias}";
$value = $field->get_value_save_entry( GFFormsModel::get_field_value( $field ), $form, null, null, null );
$where[] = $wpdb->prepare( "( {$alias}.form_id = %d AND {$alias}.meta_key = %s AND {$alias}.meta_value = %s )", $field->formId, $field_id, $value );
} else {
$join[] = "INNER JOIN {$wpdb->prefix}gf_entry_meta {$alias} ON {$_alias}.entry_id = {$alias}.entry_id";
}
}
$field_group_query = array(
'select' => $select,
'from' => $from,
'join' => implode( ' ', $join ),
'where' => sprintf( 'WHERE %s', implode( "\nAND ", $where ) )
);
$query['where'] .= sprintf( ' AND e.id IN( %s )', implode( "\n", $field_group_query ) );
return $query;
}
public function is_applicable_form( $form ) {
$form_id = isset( $form['id'] ) ? $form['id'] : $form;
return empty( $this->_args['form_id'] ) || $form_id == $this->_args['form_id'];
}
public function load_form_script( $form, $is_ajax_enabled ) {
$func = array( 'GP_Limit_Choices_Field_Group', 'output_script' );
if( $this->is_applicable_form( $form ) && ! has_action( 'wp_footer', $func ) ) {
add_action( 'wp_footer', $func );
add_action( 'gform_preview_footer', $func );
}
return $form;
}
public function add_init_script( $form ) {
if( ! $this->is_applicable_form( $form ) ) {
return;
}
$target_field_id = $this->get_target_field_id( $form, $this->_args['field_ids'] );
$args = array(
'formId' => $this->_args['form_id'],
'targetFieldId' => $target_field_id,
'triggerFieldIds' => $this->get_trigger_field_ids( $form, $this->_args['field_ids'] ),
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'hash' => $this->_args['hash'],
);
$script = 'new GPLCFieldGroup( ' . json_encode( $args ) . ' );';
$slug = implode( '_', array( 'gplc_field_group', $this->_args['form_id'], $target_field_id ) );
GFFormDisplay::add_init_script( $this->_args['form_id'], $slug, GFFormDisplay::ON_PAGE_RENDER, $script );
}
public function get_target_field_id( $form, $field_ids ) {
foreach( $field_ids as $field_id ) {
$field = GFAPI::get_field( $form, $field_id );
if ( gp_limit_choices()->is_applicable_field( $field ) ) {
return $field_id;
}
}
return false;
}
public function get_trigger_field_ids( $form, $field_ids ) {
$target_field_id = $this->get_target_field_id( $form, $field_ids );
return array_values( array_filter( $field_ids, function( $field_id ) use ( $target_field_id ) {
return $field_id != $target_field_id;
} ) );
}
public function ajax_refresh() {
// Object can be instantiated multiple times. Only listen for this specific configuration's hash.
if ( rgpost( 'hash' ) !== $this->_args['hash'] ) {
/**
* Return out if the hash doesn't match. If we exit here, other ajax_refresh() calls in other instances
* won't have the chance to run.
*/
return;
}
$entry = GFFormsModel::get_current_lead();
if( ! $entry ) {
wp_send_json_error();
}
$form = gf_apply_filters( array( 'gform_pre_render', $entry['form_id'] ), GFAPI::get_form( $entry['form_id'] ), false, array() );
$field = GFFormsModel::get_field( $form, $this->get_target_field_id( $form, $this->_args['field_ids'] ) );
if( $field->get_input_type() == 'html' ) {
$content = GWPreviewConfirmation::preview_replace_variables( $field->content, $form );
} else {
$value = rgpost( 'input_' . $field->id );
$content = $field->get_field_content( $value, true, $form );
$content = str_replace( '{FIELD}', $field->get_field_input( $form, $value, $entry ), $content );
}
wp_send_json_success( $content );
}
public static function output_script() {
?>
<script type="text/javascript">
( function( $ ) {
window.GPLCFieldGroup = 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() {
self.$form = $( '#gform_wrapper_{0}'.format( self.formId ) );
self.$targetField = $( '#field_{0}_{1}'.format( self.formId, self.targetFieldId ) );
self.$triggerFields = false;
for( var i = 0; i < self.triggerFieldIds.length; i++ ) {
var $field = $( '#field_{0}_{1}'.format( self.formId, self.triggerFieldIds[ i ] ) );
if ( ! self.$triggerFields ) {
self.$triggerFields = $().add( $field );
}
// @todo Test with multiple triggers.
else {
self.$triggerFields.add( $field );
}
}
self.$triggerFields.on( 'change', function() {
self.refresh();
} );
self.refresh();
};
self.refresh = function() {
if( ! self.$targetField.is( ':visible' ) ) {
return;
}
var data = {
action: 'gplcfg_refresh_field',
hash: self.hash
};
self.$form.find( 'input, select, textarea' ).each( function() {
data[ $( this ).attr( 'name' ) ] = $( this ).val();
} );
// Prevent AJAX-enabled forms from intercepting our AJAX request.
delete data['gform_ajax'];
$.post( self.ajaxUrl, data, function( response ) {
if( response.success ) {
self.$targetField.html( response.data );
}
} );
};
self.init();
}
} )( jQuery );
</script>
<?php
}
}
# Configuration
new GP_Limit_Choices_Field_Group( array(
'form_id' => 1485,
'field_ids' => array( 1, 2 )
) );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment