Customizing repeat schedules in the Event field
The Event field supports four repeat frequencies: Every Day, Every Week, Every Month, and Every Year. Two filters let developers adjust how a recurrence is stored and which options appear in the Repeat Frequency dropdown. This guide documents what those filters can do and, just as important, what they cannot.
Filter availability:
gk/field-event/cron-valueships since 1.1.0. It received one argument until 1.7.0, which added five more.gk/field-event/inputs/repeat-inputships since 1.4.2.
There is no released filter for adding new repeat frequencies. Read What you cannot do before attempting it.
Prerequisites #
Before you begin, ensure that you have:
- The Gravity Forms Event Field plugin installed and activated
- Basic knowledge of WordPress hooks and filters
Read Adding custom PHP code snippets to your website to learn where to place these code snippets.
How recurrence is stored #
When someone submits a repeating event, the field converts their dropdown selection into a five-part scheduling expression pinned to the event’s start date and time. The entry stores that expression, not the dropdown value.
For an event starting Saturday, March 14, 2026 at 2:30 PM:
| Selection | Stored expression | Recurrence interval | The calendar draws |
|---|---|---|---|
| Every Day | 30 14 * * * | 1 day | Every day |
| Every Week | 30 14 * * 6 | 1 week | Every Saturday |
| Every Month | 30 14 14 * * | 1 month | The 14th of each month |
| Every Year | 30 14 14 03 * | 1 year | March 14 each year |
All-day events, and events submitted without a start time, store 00 09 (9:00 AM) as the time.
Everything downstream reads this expression back by its shape:
- GravityCalendar maps the expression to one of exactly four intervals (daily, weekly, monthly, yearly) by counting wildcards, then draws occurrences by stepping that fixed interval from the start date.
- The entry edit view (WordPress admin and GravityView Edit Entry) maps the expression back to one of the four dropdown values the same way.
- The entry display renders it as prose, such as “Every Saturday at 14:30”.
These four shapes are the field’s complete recurrence vocabulary.
Changing the stored expression #
The gk/field-event/cron-value filter runs while an entry is being saved, after the expression is built and before it is stored. It runs only when the submitter selected a repeat frequency.
Its first argument is an array with the keys minute, hour, day_month, month, and day_week. Each value is a number or *. Return the modified array; the plugin joins it with spaces in that key order.
Version 1.7.0 added five more arguments describing the submission the expression came from. Callbacks written for the single-argument form keep working, since WordPress passes only as many arguments as a callback registered for.
| Argument | Type | Value |
|---|---|---|
$cron | array | The expression parts. |
$cycle | string | The submitted frequency: every_day, every_week, every_month or every_year. |
$start_date | string | The event start date, in Y-m-d format. |
$timestamp | int | The start date as a Unix timestamp. |
$is_all_day_event | bool | Whether the event runs all day. |
$start_time | string|null | The submitted start time. Null for an all-day event, and null when none was submitted. |
Example: pin all repeating events to a specific time
/**
* Store every recurrence at 6:00 PM, regardless of the submitted start time.
*
* @param array $cron The expression parts: minute, hour, day_month, month, day_week.
*
* @return array The modified expression parts.
*/
add_filter( 'gk/field-event/cron-value', function ( $cron ) {
$cron['minute'] = '00';
$cron['hour'] = '18';
return $cron;
} );Example: move weekly events to a fixed weekday
/**
* Recur weekly events on Monday instead of the submitted start date's weekday.
*
* @param array $cron The expression parts.
*
* @return array The modified expression parts.
*/
add_filter( 'gk/field-event/cron-value', function ( $cron ) {
$is_weekly = '*' !== $cron['day_week'];
if ( $is_weekly ) {
$cron['day_week'] = '1'; // Monday. Sunday is 0.
}
return $cron;
} );Example: retime one frequency only (1.7.0 and later)
/**
* Move weekly recurrences to 6:00 PM and leave every other frequency alone.
*
* @param array $cron The expression parts.
* @param string $cycle The submitted repeat frequency.
*
* @return array The modified expression parts.
*/
add_filter( 'gk/field-event/cron-value', function ( $cron, $cycle ) {
if ( 'every_week' === $cycle ) {
$cron['hour'] = '18';
}
return $cron;
}, 10, 2 );Register the callback for as many arguments as it uses. WordPress passes only that many.
Rules for this filter
- Use plain numeric values or
*only. Cron patterns such as*/2,1#3, orLare not supported. The interval mapping counts wildcard characters, so*/2in the minute slot turns a weekly event into a daily one, and the entry display cannot render pattern values. - Keep the expression in one of the four shapes shown in the table above. Any other shape produces a recurrence the calendar and edit view will misread.
- Before 1.7.0 the filter receives only the expression array. Infer the frequency from which slots are set:
day_weekset means weekly,day_monthset means monthly,day_monthandmonthset means yearly, all wildcards means daily. From 1.7.0, read$cycleinstead. - It runs at save time only. Existing entries keep the expression they were saved with.
Changing the dropdown #
The gk/field-event/inputs/repeat-input filter runs when the Repeat Frequency input renders. It receives the input’s full configuration array, including options. Use it to remove or relabel the built-in frequencies.
Example: remove the daily option
/**
* Remove "Every Day" from the Repeat Frequency dropdown.
*
* @param array $repeat The repeat input configuration.
*
* @return array The modified configuration.
*/
add_filter( 'gk/field-event/inputs/repeat-input', function ( $repeat ) {
unset( $repeat['options']['every_day'] );
return $repeat;
} );Removing an option does not change entries already saved with that frequency. Those events keep recurring, and the edit view cannot re-select the removed option.
Do not use this filter to add new options. The next section explains why.
What you cannot do #
Adding a custom option to the dropdown does not create a custom schedule. The save routine recognizes only the four built-in values. Any other value falls through and stores the daily expression. The result is silently wrong data:
- The submitter picks the custom option, for example “Every 3rd Monday”.
- The entry stores
00 09 * * *, the daily expression. - The calendar draws the event every single day.
- Reopening the entry shows “Every Day” selected. The custom choice is gone, because the entry stores the expression, not the dropdown value.
Pairing a custom option with a gk/field-event/cron-value callback does not fix this. The best a callback can do is produce one of the four supported shapes, so “Every 3rd Monday” becomes, at best, every Monday.
Schedules outside the four built-in frequencies are not expressible. That includes every two weeks, quarterly, twice monthly, “every 3rd Monday”, and “last Friday of the month”. The stored format has four shapes, the interval mapping has four outputs, and the calendar steps by a fixed interval from the start date. No filter combination changes that.
If your project needs one of these schedules, contact GravityKit support and describe the use case. This requires a plugin feature, not a code snippet.
Troubleshooting #
A custom dropdown option saves as “Every Day”
This is the expected result of an unsupported customization. Read What you cannot do.
Repeating events recur at 9:00 AM instead of the event time
All-day events, and events submitted without a start time, pin recurrence to 9:00 AM. Use gk/field-event/cron-value to store a different time.
A filter change has no effect on existing events
gk/field-event/cron-value runs when an entry is saved. Entries saved before the filter was added keep their stored expression until they are saved again.
The calendar draws a weekly event every day
The stored expression has an extra wildcard, usually from a */2-style pattern. Use plain numeric values or * in every slot.
