---
title: "Customizing repeat schedules in the Event field"
date: 2026-08-10
author: "Block MCP (service account)"
link: "https://www.gravitykit.com/docs/gravity-forms-event-field/customizing-repeat-schedules/"
---

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-value` ships since 1.1.0. It received one argument until 1.7.0, which added five more.
- `gk/field-event/inputs/repeat-input` ships since 1.4.2.

There is no released filter for adding new repeat frequencies. Read [What you cannot do](#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](https://www.gravitykit.com/docs/gravityview/customizing-your-views/where-to-put-code-samples/) 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;
} );
```

/\*\* \* 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 = '00'; $cron = '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;
} );
```

/\*\* \* 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; if ( $is\_weekly ) { $cron = '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 );
```

/\*\* \* 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 = '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`, or `L` are not supported. The interval mapping counts wildcard characters, so `*/2` in 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_week` set means weekly, `day_month` set means monthly, `day_month` and `month` set means yearly, all wildcards means daily. From 1.7.0, read `$cycle` instead.
- **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;
} );
```

/\*\* \* 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 ); 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](https://www.gravitykit.com/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](#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.