Better Inventory with Gravity Forms

Gravity Forms does not support the concept of inventory out of the box. This snippet provides an easy method for setting up simple, one-off inventory limits on a per field basis.
  • November 11, 2012: Fixed issue where database prefix was not applied via $wpdb->prefix.

  • October 1, 2014: Added support for "sum" action on [gravityforms] shortcode.

  • October 5, 2014: Added support for "remaining" action on [gravityforms] shortcode.

Let’s dive into the code first.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
<?php
/**
* Gravity Wiz // Gravity Forms // Better Inventory with Gravity Forms
*
* Implements the concept of "inventory" with Gravity Forms by allowing the specification of a limit determined by the sum of a specific field, typically a quanity field.
*
* @version 1.0
* @author David Smith <david@gravitywiz.com>
* @license GPL-2.0+
* @link http://gravitywiz.com/2012/09/19/better-inventory-with-gravity-forms/
* @copyright 2014 Gravity Wiz
*/
class GWLimitBySum {
private $_args;
function __construct($args) {
$this->_args = wp_parse_args($args, array(
'form_id' => false,
'field_id' => false,
'limit' => 20,
'limit_message' => __('Sorry, this item is sold out.'),
'validation_message' => __('You ordered %1$s of this item. There are only %2$s of this item left.'),
'approved_payments_only' => false,
'hide_form' => false
));
$this->_args['input_id'] = $this->_args['field_id'];
extract($this->_args);
add_filter("gform_pre_render_$form_id", array(&$this, 'limit_by_field_values'));
add_filter("gform_validation_$form_id", array(&$this, 'limit_by_field_values_validation'));
// add 'sum' action for [gravityforms] shortcode
add_filter( 'gform_shortcode_sum', array( $this, 'shortcode_sum' ), 10, 2 );
add_filter( 'gform_shortcode_remaining', array( $this, 'shortcode_remaining' ), 10, 2 );
if($approved_payments_only)
add_filter('gwlimitbysum_query', array(&$this, 'limit_by_approved_only'));
}
public function limit_by_field_values($form) {
$sum = self::get_field_values_sum($form['id'], $this->_args['input_id']);
if($sum < $this->_args['limit'])
return $form;
if($this->_args['hide_form']) {
add_filter('gform_get_form_filter', create_function('', 'return "' . $this->_args['limit_message'] . '";'));
} else {
add_filter('gform_field_input', array(&$this, 'hide_field'), 10, 2);
}
return $form;
}
public function limit_by_field_values_validation($validation_result) {
extract($this->_args);
$form = $validation_result['form'];
$exceeded_limit = false;
foreach($form['fields'] as &$field) {
if($field['id'] != intval($input_id))
continue;
$requested_value = rgpost("input_" . str_replace('.', '_', $input_id));
$field_sum = self::get_field_values_sum($form['id'], $input_id);
if($field_sum + $requested_value <= $limit)
continue;
$exceeded_limit = true;
$number_left = $limit - $field_sum >= 0 ? $limit - $field_sum : 0;
$field['failed_validation'] = true;
$field['validation_message'] = sprintf($validation_message, $requested_value, $number_left);
}
$validation_result['form'] = $form;
$validation_result['is_valid'] = !$validation_result['is_valid'] ? false : !$exceeded_limit;
return $validation_result;
}
public function hide_field($field_content, $field) {
if($field['id'] == intval($this->_args['input_id']))
return "<div class=\"ginput_container\">{$this->_args['limit_message']}</div>";
return $field_content;
}
public static function get_field_values_sum($form_id, $input_id) {
global $wpdb;
$query = apply_filters( 'gwlimitbysum_query', array(
'select' => 'SELECT sum( ld.value )',
'from' => "FROM {$wpdb->prefix}rg_lead_detail ld",
'join' => '',
'where' => $wpdb->prepare( "WHERE ld.form_id = %d AND CAST( ld.field_number as unsigned ) = %d", $form_id, $input_id )
), $form_id, $input_id );
$wpdb->show_errors();
$sql = implode( ' ', $query );
$result = $wpdb->get_var( $sql );
return intval( $result );
}
public static function limit_by_approved_only( $query ) {
global $wpdb;
$query['from'] .= " INNER JOIN {$wpdb->prefix}rg_lead l ON l.id = ld.lead_id";
$query['where'] .= ' AND l.payment_status = \'Approved\'';
return $query;
}
public function shortcode_sum( $output, $atts ) {
$atts = shortcode_atts( array(
'id' => false,
'input_id' => false
), $atts );
extract( $atts ); // gives us $id, $input_id
return intval( self::get_field_values_sum( $id, $input_id ) );
}
public function shortcode_remaining( $output, $atts ) {
$atts = shortcode_atts( array(
'id' => false,
'input_id' => false,
'limit' => false
), $atts );
extract( $atts ); // gives us $id, $input_id
$remaining = $limit - intval( self::get_field_values_sum( $id, $input_id ) );
return max( 0, $remaining );
}
}
# Configuration
new GWLimitBySum( array(
'form_id' => 363,
'field_id' => 2.3,
'limit' => 2,
'limit_message' => 'Sorry, there are no more tickets!',
'validation_message' => 'You ordered %1$s tickets. There are only %2$s tickets left.',
'approved_payments_only' => false,
'hide_form' => false
) );

How do I install this snippet?

Easy peasy. Just copy and paste the code above into your theme's functions.php file.

Do I need to modify this snippet to work with my form?

You don’t have to modify the snippet itself. Just the parameters with which you initialize it.

new GWLimitBySum( array(
'form_id' => 363,
'field_id' => 2.3,
'limit' => 2,
'limit_message' => 'Sorry, there are no more tickets!',
'validation_message' => 'You ordered %1$s tickets. There are only %2$s tickets left.',
'approved_payments_only' => false,
'hide_form' => false
) );

Parameters

  • $form_id the ID of the form you are working with.
  • $field_id the ID of your product or quantity field. If using a Single Product field, you’ll need to specify the quantity input ID which will always be {field ID}.3 (ie if the field ID is 12, the quantity input ID will be 12.3). If using a separate Quantity field, simply specify the field ID.
  • $limit the number of this item you have available.
  • $limit_message the message which should be displayed to users when the product limit has been reached. You can get fancy with this and add HTML as well. Be sure to escape any double quotes with a backslash. Here’s a more advanced example:
    $sum_limit_message = '<div style="border: 1px solid #e6db55; background-color: #FFFFE0; padding: 10px;">Sorry, this show is sold out.</div>';
    Better Inventory: Limit Message
  • $validation_message the validation message which should be displayed on the field if the limit has not been reached, but the user’s requested quantity would exceed the product limit.
    Better Inventory: Limit Validation Message
  • $approved_payments_only true/false indicate whether all submissions for this field should be counted against the limit or only submissions with an approved payment. You’ll want to be careful here when using PayPal Standard due to the delay between the form submission and the payment being approved. It could lead to users exceeding the limit.
  • $hide_form by default this snippet will only hide the field when the limit has been reached. If you would rather hide the entire form, set this to true.

Comments

  1. says

    Hiya David,

    Thanks for the code! I was trying to use this code for multiple forms on the same site at once. So basically I have a form that takes enrollments for a class, the class meets over multiple sessions and so every instance of the class has it’s own form (6 total forms). Is there a way to use this code for multiple forms? If I call new GWLimitBySum() more than once, I get a WP database error and adding additional form_ids on the same call doesn’t work for more than the first form it seems. Any insight you could give would be appreciated. Thanks!

    • says

      Thx for the help David but still no dice. (#):(

      I’m using the exact code below:

      new GWLimitBySum( array( 'form_id' => 7, 'field_id' => 11.3, 'limit' => 16, 'limit_message' => 'Sorry, there is no more space in this class.!', 'validation_message' => '', 'approved_payments_only' => true, 'hide_form' => false ) );

      new GWLimitBySum( array( 'form_id' => 8, 'field_id' => 11.3, 'limit' => 16, 'limit_message' => 'Sorry, there is no more space in this class.!', 'validation_message' => '', 'approved_payments_only' => true, 'hide_form' => false ) );

      And then I get the following screen : screen shot

      Thoughts?

    • says

      Hey David,

      Thanks for the code! It DID take away the error message but unfortunately it didn’t work for multiple forms and for one form it wouldn’t pop the “limit_message” and instead would just Zero the form total… I had to change “hide_form” to “true” in order to get it where the user wouldn’t be confused as to what was going on. But I think it’s probably very close!

  2. Jack says

    Hi David,

    This is great however, any idea if it would work for the following:

    I need to have my users select 1 of 10 categories in a radio button list and, to better the user experience, I’d like to show the remaining quantity for each category at the end of each radio button description. Then, when the user selects the radio button, a payment gateway will appear.

    Thanks!

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>