Skip to content

Recurring Events

What Are Recurring Events?

Recurring events are a WordPress-only feature for the NOMA website. They are separate from Givebutter event sync: no Givebutter campaign is involved. Staff create events in WP admin and set a recurrence rule (e.g. every Monday, or the 2nd Thursday of each month). The site then shows one occurrence per date on the List, Grid, and Calendar.

  • Manual — Created and edited in WordPress; not synced from Givebutter.
  • Free, non-ticketed — No registration or ticketing; ideal for awareness/support events (e.g. "Lunch & Listen every Monday," "Family Support Group every Tuesday").
  • Givebutter-synced (ticketed) events never have recurrence; the recurrence meta box is hidden for them.

One Post = One Series

One noma_events post represents one series (e.g. "Lunch & Listen every Monday"). In the admin, staff set:

  • Repeat — None (default), Weekly, or Monthly
  • Interval — Every N weeks or months (e.g. every 2 weeks)
  • Weekdays (weekly) — Which days (e.g. Mon, Wed)
  • Month rule (monthly) — e.g. 1st Monday, 2nd Thursday, Last Friday
  • End date (optional) — Last date of the series

The theme stores these in post meta and exposes them on the REST API. The front end expands the rule into individual occurrences so List, Grid, and Calendar each show one item per occurrence (e.g. one card per Monday).

Key Decision: Client-Side Expansion

We do not expand recurring events in the WordPress REST API. The API returns one event per post (with recurrence meta).

The hello-noma theme's React app expands recurring events into occurrences in the useEvents hook: expandRecurringEvents(data, today, sixMonthsOut). List, Grid, and Calendar all receive one item per occurrence (e.g. one card per Monday). Filters (e.g. "Upcoming Only") then run on occurrence dates.

Rationale: Single expansion point, no API changes, filters work on occurrence date; List/Grid/Calendar behave consistently.

What Gets Stored (Post Meta)

Recurrence is stored in private post meta (theme exposes these on the REST API):

MetaPurpose
_recurrence_typenone | weekly | monthly
_recurrence_intervalEvery N weeks/months (e.g. 1 = every week)
_recurrence_weekdaysFor weekly: which days (e.g. 1,3,5 for Mon, Wed, Fri)
_recurrence_month_ruleFor monthly: e.g. 1st_mon, 2nd_thu, last_fri
_recurrence_end_dateOptional last date of series (Y-m-d)

Existing fields like _start_date / _start_time define the first occurrence (template for time and duration). Givebutter-synced events always have _recurrence_type none or empty; the recurrence meta box is hidden for ticketed events.

Where It's Implemented (Developer Reference)

  • WordPress (hello-noma theme): Event Recurrence meta box, save logic, REST exposure of recurrence meta. Recurrence is only for non-ticketed events.
  • Frontend (theme): src/lib/recurrence.jsexpandRecurringEvents, getRecurrenceDescription, getNextOccurrences; useEvents hook expands once for the next 6 months; EventCalendar, EventCard, EventCardList use the pre-expanded events; single event page shows "This is a recurring event" and the next 5 occurrences.