I've often found that clients would like to limit the amount of submissions on their gravity forms in various ways. For example, some folks would like to limit a specific email address to just 1 submission per week.
This snippet is perfect for creating that sort of setup.
For ease of use you may copy/paste these snippets into your functions.php file, or copy and paste this code into your own plugin. It’s also quite easy to adjust this code to your specific country or discount/fee scheme.
add_filter( 'gform_validation', array( 'GFSubmissionLimitService', 'validate'), 10, 2 ); add_filter( 'gform_form_settings_fields', array( 'GFSubmissionLimitService', 'settings'), 10, 2 ); class GFSubmissionLimitService { /** * * Define our custom settings * * @param $fields * @param $form * @return array */ public static function settings( $fields, $form ) { $fields['restrictions']['fields'][] = array( 'type' => 'checkbox', 'name' => 'limitSubmissionsByField', 'label' => 'Limit Submissions By Field', 'tooltip' => '<button onclick="return false;" onkeypress="return false;" class="gf_tooltip tooltip tooltip_form_limit_entries" aria-label="<strong>Limit Number of Submissions By Field</strong>Enter a number in the input box below to limit the number of entries allowed by field value for this form. The form will reject submissions over the maximum."> <i class="gform-icon gform-icon--question-mark" aria-hidden="true"></i> </button>', 'choices' => [ [ 'name' => 'limitSubmissionsByField', 'label' => 'Enable Limit Submissions By Field' ] ], 'fields' => [ [ 'name' => 'limitSubmissionsNumber', 'type' => 'text_and_select', 'label' => 'Number of Entries', 'dependency' => [ 'live' => true, 'fields' => [ [ 'field' => 'limitSubmissionsByField' ] ] ], 'inputs' => [ 'text' => [ 'name' => 'limitSubmissionsByFieldCount', 'input_type' => 'number', 'required' => true ], 'select' => [ 'name' => 'limitSubmissionsByFieldPeriod', 'choices' => [ [ 'label' => 'total', 'value' => null ], [ 'label' => 'per day', 'value' => 'day' ], [ 'label' => 'per week', 'value' => 'week' ], [ 'label' => 'per month', 'value' => 'month' ], [ 'label' => 'per year', 'value' => 'year' ] ] ] ], ], [ 'name' => 'limitSubmissionsField', 'type' => 'field_select', 'label' => 'Which Field to Check?', 'required' => true, 'dependency' => [ 'live' => true, 'fields' => [ [ 'field' => 'limitSubmissionsByField' ] ] ], ], [ 'name' => 'limitSubmissionsMessage', 'type' => 'textarea', 'label' => 'Entry Limit Reached Message', 'allow_html' => true, 'dependency' => [ 'live' => true, 'fields' => [ [ 'field' => 'limitSubmissionsByField' ] ] ], ] ] ); return $fields; } /** * * Validate this form submission based on our own custom logic * * @param $validation_result * @return mixed */ public static function validate( $validation_result ) { $form = $validation_result['form']; $args = []; // The settings we need from the form object. $settings = [ 'enabled' => $form['limitSubmissionsByField'] ?? false, 'limit' => $form['limitSubmissionsByFieldCount'] ?? false, 'period' => $form['limitSubmissionsByFieldPeriod'] ?? 'total entries', 'field' => $form['limitSubmissionsField'] ?? false, 'message' => $form['limitSubmissionsMessage'] ?? "Sorry, you cannot submit this form right now. Try again later", ]; // Can we validate this form? if( ! self::canValidateThisForm( $form, $settings ) ) return $validation_result; $total_submissions = self::getTotalEntriesFor( $form['id'], $settings['period'], // period $settings['field'], // field rgpost( 'input_' . $form['limitSubmissionsField'] , true ) // value ); // If we're lower than the limit, continue. if( $total_submissions < $settings['limit'] ) return $validation_result; // If we're here, then the form is invalid. Handle appropriately: // Mark as invalide $validation_result['is_valid'] = false; // add error message to the field selected by the user. foreach( $form['fields'] as &$field ) { if ( $field->id == $settings['field'] ) { $field->failed_validation = true; $field->validation_message = $settings['message'] . sprintf(" (Maximum %d)", $settings['limit'] ); break; } } // return the form $validation_result['form'] = $form; return $validation_result; } /** * * Count Gravity Forms entry for this period, for this fiield id, which has this value. * * @param $form_id * @param $period * @param $field_id * @param $value * @return int */ protected static function getTotalEntriesFor( $form_id, $period, $field_id, $value ) { $args = self::getQueryArgsForPeriod( $period ); // merge our args into the default query: $args = array_merge([ 'status' => 'active', 'field_filters' => [ 'mode' => 'any', [ 'key' => $field_id, 'value' => $value ] ] ], $args ); // count how many match this email and this contest in active status? return intval( \GFAPI::count_entries( $form_id, $args ) ); } /** * * Checks to see if the settings and form submission allow for us to validate this form. * * @param $form * @param $settings * @return bool */ protected static function canValidateThisForm( $form, $settings ) { // If not enabled, skip. if( ! $settings['enabled'] ) return false; // If no limit is set, skip if( ! $settings['limit'] || $settings['limit'] <= 0 ) return false; // If no field is set, skip if( ! $settings['field'] ) return false; $submitted_field_value = rgpost( 'input_' . $form['limitSubmissionsField'] , true ); // If no value was set, we cannot compare it, so return. if( ! $submitted_field_value ) return false; return true; } /** * * Sets the query args for a given period * * @param $period * @return array * @throws \Exception */ protected static function getQueryArgsForPeriod( $period ) { // If we're checking total submissions, we dont need a date query and return an empty array. if( $period == 'total' ) return []; // Get WordPress's current timezone time $now = new \DateTime( current_time('mysql') ); $start = clone $now; $end = clone $now; // default is per day. $start->setTime(0,0,1); // beginning of day $end->setTime(23,59,59); // end of day // Adjust our start time to the period provided $start->modify("-1 {$period}}"); // the period should be something like 'day', 'week', 'month' or 'year' // retuen our start-end date query. return [ 'start_date' => $start->format('Y-m-d'), 'end_date' => $end->format('Y-m-d') ]; } }