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
* 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 <>
* @license GPL-2.0+
* @link
* @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'];
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 );
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) {
$form = $validation_result['form'];
$exceeded_limit = false;
foreach($form['fields'] as &$field) {
if($field['id'] != intval($input_id))
$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)
$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 );
$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 = 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
) );


  • $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.


  1. says

    Hi David,

    Is there a way to call your snippet from a post where you pass the limit parameter from a custom field specified within that post? (And maybe even the form-id parameter) That way it would be possible to use it to registere for different events with a different amount of available seats.

    Thanks, Carl

    • David Smith says

      The issue is you would also need to limit by the post ID as well so that when using the same form, only entries specific to the current post are applied to the limit. I’m still waiting to hear back from another user on their interest in commissioning this extra functionality. If you’d like to commission it, please feel free to get in touch.

  2. Ian says

    Hi This is fantastic and could be just what I’m after.

    What I’m trying to achieve is a custom post type called events. Each event has a different price and different limit to the number of spaces.

    At the moment, we’d have to create a gravity form for each event and edit the above code. Sadly, this isn’t a great method.

    Is there any way 2 custom fields: Price and Limit could be added to each event. When someone then books/pays, it gets those values and just uses one generic form?

    Happy to pay for this if you could provide a cost

    Thanks for your time

  3. Tommie says

    Hi David,

    Does this snippet work in this case:

    I got a simple product for a ticket, the buyer can buy a ticket extra for his/her partner.

    No product value field is needed the person just need to tick a checkbox or so, that he/she will order a ticket extra. The amount gets doubled and the inventory will be -2 tickets.

    So it all comes from 1 inventory.

    How would you do it, or is it not possible with this snippet?

    Gr. Tom

    • David Smith says

      Hi Tom, it isn’t possible with this snippet alone. The way I might achieve this is to use a little jQuery to add +1 to the value in the quantity field for the ticket product when it is checked and then -1 when the checkbox is unchecked.

  4. Tommie says

    My case:

    I hold 2 inventories for a product (Variable product). Is this snippet possible with something like that…

    Can i hire you for some small things…

    Gr. Tom

  5. says

    Hi there! Great snippet!!

    How can I print the remaining seats? I am using ACF Pro and using the_field(“the_capacity”) to print the capacity.

    Cheers, Fernando.

    • David Smith says

      Hey Fernando, I’ve updated the snippet to provide support for a “remaining” shortcode:

      [gravityforms action="remaining" id="363" input_id="2.3" limit="50" /]

    • Zack says

      I’m using the Gravity Forms Add-On for WooCommerce. Is there a way to show the remaining seats by making changes to the “new GWLimitBySum” function within functions.php?

    • David Smith says

      It’s possible but would require a decent bit of customization. I’m assuming the inventory is per product within the form rather than for the WooCommerce product that “hosts” the Gravity form? The issue here is that just because a user adds a GF-configured product to the WC cart, does not mean that the user checked out. Therefore, you could end up with your inventory exhausted even though only a few people actually successfully ordered the item. If you’re looking for a quick solution, might be able to help you here.

  6. says

    Hi David, In your example (selling tickets), is there a way to always show “available tickets” instead of showing only when the quantity exceeds the available tickets via $validation_message? With this way I believe I can encourage customer/visitor to buy limited tickets. Thank you in advance! Regards, prSetiadi

    • David Smith says

      Hey prSetiadi, I’ve updated the snippet to add support for a “sum” action on the [gravityforms] shortcode. Example:

      [gravityforms action="sum" id="363" input_id="2.3" /]

  7. Darko says

    Great idea. Thank you. Can this code work with a standard drop down option? Or products as drop down/radio buttons? Each of the options should have a limit/quantity?

  8. Mario Gil says

    Hello and thanks for the addon.

    Just one question. There is a way to add the limit for two products.

    Thus, I have A and B, but I want got the limit of A+B, no the limit of A and the limit of B.

    Any solution?

    Thank you

    • David Smith says

      Hi Mario, it is possible and the hook is available in the code that would make such a modification possible but it would required additional code to accomplish. The hook is “gwlimitbysum_query” which lets you modify the query that is made to retrieve the current quantity of the specified product that has been ordered. You could update the query to include the quantity of a secondary product as well.

      If you’re interested in commissioning me to write such an enhancement, get in touch.

  9. says

    This is a great solution. I was referred to you by Gravity forms support – high praise!

    I have one question.

    What happens if I end up changing the available seat limit in the php once sales have begun? Sounds like a crazy requirement but I’ll explain.

    I have to launch my event early tomorrow morning. I’m selling tickets with limited inventory. After sales begin I’m likely to receive a more accurate limit than the one I have right now. If I start out offering 40 tickets and later find out my real limit is 50 (or worse, 30) can the code/database account for that? Or, would I need to make a new form with different ID and just relaunch with a new form and limit?

    Thanks for any help you may be able to provide.

    • David Smith says

      Hi Julian, you can change the limit at any time and this snippet will continue to work as expected. The “inventory” in this case is entry-based. So if on Day 1 you have a limit of 20 and 5 entries are submitted, the available inventory is now 15. If on Day 2 to you increase the limit to 30, the available inventory would now be 25 with the 5 entries submitted the prior day still deducted from the increased limit.

  10. says

    Would like to request a quote for custom code that would send a notification email when the inventory capacity has been reached for a field. Please contact me.

  11. Jessie Matanky says

    Is there a way to change the value of the # of submissions available based on a post meta value?

    this is the code that I have:

    ID, 'tickets_available', true); ?> 3, 'field_id' => $post->ID.5, 'limit' => $submit_limit, '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 )); ?>

    but I dont think it’s working properly.

    • David Smith says

      Hey Jessie, just wanted to follow up to your comment here. My brother should be getting back with you in the next day or so with a quote on getting this to work correctly. The basic premise is that you need to limit by two fields rather than one: 1) the quantity field and 2) an additional field that tracks which “event” the form was submitted for.

  12. John says

    I was wondering if this could be used in conjunction with the datepicker? i.e. Our inventory is a fixed number that can be rented out per day- so the days when the inventory is all checked out would be grayed out on the datepicker?

    • David Smith says

      Certainly possible but not without additional custom work. This would require modifications to how this script checks for inventory and some extra modifications to gray out the unavailable dates in the datepicker.

  13. Karin says

    I have 6 “products” in my form with a limiter.. 6 dates with 120 places available each date. But as soon as one of the dates is sold out, the form is not working anymore. It gives the message that there is an error without pointing out what the error is. I think it has troubles with dealing with one sold-out product. Any idea how to solve that?

    • karin says

      since I didn’t get this working, I made 6 forms, 1 form for each date. But still it has some troubles with the limit. On each form I set the limit. But when I order some and the next time I want to order more I get the message that there are only X items left where X is less than the limit minus what I have ordered before (checked entries… mine was the only entrie) Deleted all entries permanently, tried again. Limit is 120, order 100 first time, ordered 10 next time. Message you’ve ordered 10 items, there are only 5 items left. Or I order 110 items the first time, next time: sold out. And before trying, I always remove the entries permanently.

  14. jose says

    hello David

    I’m trying to create a list of topics for users , and i want to limit the topics picked by users.

    user will select any of the topics listed (topic 1- 15) after user selects the topic, he or she will have to register for the topic’s chosen. now i will like to limit the selection of each topic by 3, means only 3 users can register for the same topic.

    i don’t understand how to add or set ( field_id ) to each of the topics that i will like to limit inside the form .

    please help

    I have sofar done :

    new GWLimitBySum(array( ‘form_id’ => 8, ‘field_id’ => 13.3, ‘limit’ => 3, ‘limit_message’ => ‘Sorry, this topic is close!’, ‘validation_message’ => ‘You ordered %1$s tickets. There are only %2$s tickets left.’, ‘approved_payments_only’ => false, ‘hide_form’ => false ));

  15. Jesse says

    I was wondering if there was any way to have this not limit the registration, but rather trigger a waiting list. So to add a hidden field to the form that denotes everyone signed up after the limit as being on the waiting list?

    • David Smith says

      Hm… with some modification, you could extend this class and instead of adding validation errors to fields in the limit_by_field_values_validation() method, you could populate a hidden field on your form with a flag, indicating whether it should be considered on the waiting list or not.

  16. says

    Have an event limited to 20 guests max. Each guest can be one of two categories, different price for each category. Can I set a combined total of 2 fields with Better Inventory with Gravity Forms? Each form can register anywhere from 1 to all 20 guests.

    • David Smith says

      Hi Randy, do you have a link to the form in question? It would help me understand your request better if I had a visual. :)

  17. says

    I found your snippet and it looks useful. But I have multiple products (the show has multiple dates and every date has it’s own nummer of seats). how can I add this limit on every product?



    • David Smith says

      Hi Karin, you can create multiple instances of the class like so:,15 You’ll notice the only difference between to the two instances is the “field_id” parameter. You’ll need to add a new instance for each product on your form and modify the other parameters as needed.

    • David Smith says

      Hi Atlante, I was unable to access that page. Getting an authentication error when I used the provided login.

  18. says

    Thank you for the code. I appreciate your prompt response. My question is would this work in my situation where:

    End users are being asked to reserve 1 of 8 half-hour blocks for a massage at a Valentine Day event.

    In other words, between 10 and 11 am, if 10 slots are opened, I would want gf to remove that spot from the form.

    • David Smith says

      The GP Limit Choices is probably a better fit for this. You can set up each time slot as a choice on the field and then set a limit of “8” so only 8 massages can be schedule per time slot. Let me know if I misunderstood what you’re trying to do.

  19. says

    Hey David,

    Have there been any updates to this snippet? We have tried it and can’t seem to get it to work. Plus, our form is for a registration for classes at a pre-school and there are multiple options with multiple number availabilities per class.

    Thanks for the response.


    • David Smith says

      Hey Nate, nope, this is the most up to date version of this code. I just tested locally and didn’t run into any issues. If you can send me a copy of your functions.php and a link where I can view the form it isn’t working on, I’ll let you know if I can see any issues.

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=""> <strike> <strong>