Share Limits Across Multiple Fields (and Forms)

NOTE: This snippet only works with Gravity Forms 2.3 or greater.

Adds support for specifying groups of fields which share the same limit. For example, if you had two fields with a limit of 10, selections from both fields would contribute to that limit.

Code

Filename: gplc-shared-limits.php

<?php
/**
 * Gravity Perks // GP Limit Choices // Share Limits Across Multiple Fields (and Forms)
 *
 * NOTE: This snippet only works with Gravity Forms 2.3 or greater.
 *
 * Adds support for specifying groups of fields which share the same limit. For example, if you had two fields with a
 * limit of 10, selections from both fields would contribute to that limit.
 *
 * @version   2.1
 * @author    David Smith <david@gravitywiz.com>
 * @license   GPL-2.0+
 * @link      https://gravitywiz.com/
 */
class GPLS_Shared_Limits {

	public $_args = array();

	public function __construct( $args = array() ) {

		$this->_args = wp_parse_args( $args, array(
			'form_id'      => false,
			'field_groups' => array(),
			'form_groups'  => array(),
		) );

		// 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' ) );

	}

	public function init() {

		if ( ! is_callable( array( 'GFFormsModel', 'get_database_version' ) ) ) {
			return;
		}

		add_filter( 'gwlc_choice_counts_query', array( $this, 'modify_choice_counts_query' ), 10, 2 );
		add_filter( 'gplc_requested_count', array( $this, 'modify_requested_count' ), 10, 2 );

	}

	public function modify_choice_counts_query( $query, $field ) {

		if ( ! $this->is_applicable_form( $field->formId ) ) {
			return $query;
		}

		if ( ! empty( $this->_args['form_groups'] ) ) {
			$query = $this->modify_query_for_form_groups( $query, $field );
		}

		if ( ! empty( $this->_args['field_groups'] ) ) {
			$query = $this->modify_query_for_field_groups( $query, $field );
		}

		return $query;
	}

	public function modify_query_for_field_groups( $query, $field ) {
		global $wpdb;

		$from_search  = $wpdb->prepare( '(em.meta_key = %s OR em.meta_key LIKE %s)', $field['id'], $wpdb->esc_like( $field['id'] ) . '.%' );
		$from_replace = array();

		foreach ( $this->_args['field_groups'] as $field_group ) {

			if ( ! in_array( $field['id'], $field_group ) ) {
				continue;
			}

			foreach ( $field_group as $field_id ) {
				$from_replace[] = $wpdb->prepare( 'em.meta_key = %s OR em.meta_key LIKE %s', $field_id, $wpdb->esc_like( $field_id ) . '.%' );
			}
		}

		if ( ! empty( $from_replace ) ) {
			$from_replace  = sprintf( '( %s )', implode( ' OR ', $from_replace ) );
			$query['from'] = str_replace( $from_search, $from_replace, $query['from'] );
		}

		return $query;
	}

	public function modify_query_for_form_groups( $query, $field ) {
		global $wpdb;

		foreach ( $this->_args['form_groups'] as $form_group ) {

			if ( ! $this->is_form_group_field( $field, $form_group ) ) {
				continue;
			}

			$query['where'] = str_replace( sprintf( 'AND em.form_id = %d', $field->formId ), '', $query['where'] );

			$join_conditions = array();
			foreach ( $form_group as $form_id => $field_ids ) {
				$field_clauses = array();
				if ( ! is_array( $field_ids ) ) {
					$field_ids = array( $field_ids );
				}
				foreach ( $field_ids as $field_id ) {
					$field_clauses[] = "em.meta_key = '{$field_id}' OR em.meta_key LIKE '{$field_id}%'";
				}
				$join_conditions[] = "( em.form_id = {$form_id} AND ( " . implode( ' OR ', $field_clauses ) . ' ) )';
			}

			$query['from'] = sprintf( "FROM {$wpdb->prefix}gf_entry e INNER JOIN {$wpdb->prefix}gf_entry_meta em ON em.entry_id = e.id AND ( %s )", implode( "\nOR\n", $join_conditions ) );

		}

		return $query;
	}

	public function modify_requested_count( $requested_count, $field ) {

		if ( ! $this->is_applicable_form( $field['formId'] ) ) {
			return $requested_count;
		}

		foreach ( $this->_args['field_groups'] as $field_group ) {

			if ( ! in_array( $field->id, $field_group ) ) {
				continue;
			}

			$selected_choices       = gp_limit_choices()->get_selected_choices( $field );
			$primary_choice         = reset( $selected_choices );
			$shared_requested_count = 0;

			remove_filter( 'gplc_requested_count', array( $this, 'modify_requested_count' ) );

			foreach ( $field_group as $field_id ) {

				$form        = GFAPI::get_form( $field->formId );
				$group_field = GFFormsModel::get_field( $form, $field_id );

				$selected_choices = gp_limit_choices()->get_selected_choices( $group_field );
				$selected_choice  = reset( $selected_choices );

				if ( $selected_choice['value'] == $primary_choice['value'] ) {
					$shared_requested_count += gp_limit_choices()->get_requested_count( $group_field );
				}
			}

			add_filter( 'gplc_requested_count', array( $this, 'modify_requested_count' ), 10, 2 );

			break;

		}

		return isset( $shared_requested_count ) ? intval( $shared_requested_count ) : $requested_count;
	}

	public function is_applicable_form( $form ) {

		$form_id            = is_array( $form ) ? $form['id'] : $form;
		$is_applicable_form = false;

		if ( ! empty( $this->_args['form_groups'] ) ) {
			foreach ( $this->_args['form_groups'] as $form_group ) {
				$is_applicable_form = $this->is_form_group_form( $form, $form_group );
				if ( $is_applicable_form ) {
					break;
				}
			}
		} else {
			$is_applicable_form = $form_id == $this->_args['form_id'];
		}

		return $is_applicable_form;
	}

	public function is_form_group_form( $form, $form_group ) {
		$form_id = is_array( $form ) ? $form['id'] : $form;
		return in_array( $form_id, array_keys( $form_group ) );
	}

	public function is_form_group_field( $field, $form_group ) {
		return $this->is_form_group_form( $field->formId, $form_group ) && in_array( $field->id, $this->get_form_group_fields( $form_group ) );
	}

	public function get_form_group_fields( $form_group ) {
		$form_group_fields = array();
		foreach ( $form_group as $form_id => $field_ids ) {
			if ( ! is_array( $field_ids ) ) {
				$field_ids = array( $field_ids );
			}
			$form_group_fields = array_merge( $form_group_fields, $field_ids );
		}
		return $form_group_fields;
	}

}

# Configuration

new GPLS_Shared_Limits( array(
	'form_id'      => 123,
	'field_groups' => array(
		array( 1, 2 ),
	),
) );

/**
 * Share fields across multiple forms by using the `form_groups` parameter and an array for each form group with the
 * key of the form ID and the value of the field ID on that form to share limits.
 *
 * Note: This method cannot be used to share limits for fields on the same form.
 */
new GPLS_Shared_Limits( array(
	'form_groups' => array(
		array(
			123 => 3,
			124 => 4,
		),
		array(
			123 => 5,
			124 => 6,
		),
	),
) );

/**
 * Share fields across the same *and* other forms by using the `form_groups` parameter and passing each form's fields
 * as an array.
 */
new GPLS_Shared_Limits( array(
	'form_groups' => array(
		array(
			123 => array( 1, 2 ),
			124 => array( 3, 4 ),
		),
	),
) );

Leave a Reply

Your email address will not be published. Required fields are marked *

  • Trouble installing this snippet? See our troubleshooting tips.
  • Need to include code? Create a gist and link to it in your comment.
  • Reporting a bug? Provide a URL where this issue can be recreated.

By commenting, I understand that I may receive emails related to Gravity Wiz and can unsubscribe at any time.