Events — Reference
The Events surface is the listings engine for time-bound activities — workshops, webinars, conferences, store openings, product launches, classes, meetups, anything with a start time, an end time, and a venue. It owns the event records themselves, the recurrence model that lets one record expand into a recurring series, the venue records that anchor in-person events, the RSVP integration that captures who is attending, and the calendar-feed export that lets external calendars subscribe to the listing.
This page is a reference for platform engineers and integrators who need to understand the surface before extending it, scripting against it, or migrating a legacy event-plugin set (The Events Calendar, Events Manager, custom CPT) into SGEN. Customer-facing walkthroughs for publishing an event and managing RSVPs live in the customer docs set; this page describes the shape of the surface, not the editorial flow.
Overview
Events live under the Events module in SG-Admin. The module renders four primary views — the event list, the event create / edit form, the per-event RSVP list, and the calendar view (events laid out by month or week) — and exposes a write surface for create, update, duplicate, cancel, soft delete, restore, recurrence expansion, RSVP export, and calendar-feed regeneration.
The module is paired by convention: one half renders the views and prepares the data (event list, RSVP roster, calendar view, venue picker), the other half handles writes and returns AJAX responses. The pairing matches the broader SG-Admin convention used across Pages, Posts, Forms, Media, and Users.
Where it lives in SG-Admin:
- Sidebar: SG-Admin → Events
- URL prefix:
/sg-admin/events/ - View templates:
application/views/Admin/Events/
Events are paired with the Venues sub-module (an in-module surface, not a separate top-level module) that stores reusable venue records — physical addresses, map coordinates, capacity, accessibility metadata. One venue record can anchor many events, and editing a venue updates every event attached to it.
┌──────────────────────────────────────────────────────────────────────┐│ SG-Admin → Events [+ New event]│├──────────────────────────────────────────────────────────────────────┤│ Title Date Venue RSVPs Status││ ───────────────────── ──────────────── ─────────── ────── ─────││ Spring product launch 2026-06-04 10:00 Main hall 218 active││ Friday workshop 2026-05-29 14:00 Studio B 47 active││ Customer roundtable 2026-05-23 09:00 Remote 92 active││ Weekly office hours every Tue 15:00 Remote 12/wk series││ Q1 launch event 2026-02-10 18:00 Old venue — past ││ ││ [⋯ Edit] [⋯ RSVPs] [⋯ Duplicate] [⋯ Cancel] [⋯ Export feed] │└──────────────────────────────────────────────────────────────────────┘Actions
The Events surface exposes the following operations. Each is described by what it does to the data and to the public listing, not by its internal method name.
List and search events
Returns the event records, paginated, with title, start date, venue, RSVP count, and status columns. Supports column sort, free-text filter by title or venue, date-range filter (upcoming / past / specific window), and status filter (active / cancelled / draft / past / trash). The default view shows upcoming-and-active.
Create event
Opens an empty event form. Required fields at minimum: title, start time, end time, venue (or "remote" / "TBD"), description. Optional fields cover capacity, RSVP requirement, ticket price (when paired with the Commerce module), cover image, hero image, social-share metadata, hosted-by attribution, and recurrence rule.
On submit, the surface validates the time window (end after start, no negative duration), validates the venue capacity against any pre-existing RSVP count, persists the record, and returns the new event identifier. The event publishes immediately if status is active; draft events do not surface on the public listing.
Edit event
Loads an existing event into the same form shape used for create, pre-populated. Submit replaces the stored definition. Edits to a recurring series prompt the operator: apply to this occurrence only, to this and future occurrences, or to the entire series. The choice rewrites the corresponding subset of occurrence records.
Duplicate event
Creates a new event with the same definition (title carries a copy-suffix), a fresh RSVP roster, and a new identifier. Used to spin up a sibling event from a known-good template.
Cancel event
Moves the event into a cancelled state. The public listing renders the event with a cancelled banner; the RSVP roster receives a cancellation notification email; the calendar feed marks the occurrence as cancelled (STATUS:CANCELLED per iCalendar). Cancelled events are not deleted — the historical record remains for audit and for refund processing if tickets were sold.
Soft delete
Marks the event as trashed. Trashed events disappear from the public listing and from the operator's default views. Past events that have already happened can be soft-deleted to clean up the active list without losing historical RSVP records.
Restore
Returns a trashed event to its prior state (active / cancelled / draft). The public listing resumes rendering for active events; cancelled events remain marked as cancelled.
Recurrence expansion
A series record (e.g. "every Tuesday 3pm") materializes into individual occurrence records at create time and on a rolling expansion window (default 90 days ahead). The recurrence-expansion job runs nightly and creates the next batch of occurrences as the rolling window advances. Each occurrence carries its own RSVP roster, can be edited independently of the series, and can be cancelled individually.
Editing a single occurrence detaches it from the series template — future series edits no longer overwrite that occurrence. Operators see a "detached from series" indicator in SG-Admin.
Manage RSVPs
The per-event RSVP list. Shows attendee name, email, party size, RSVP timestamp, response (yes / no / maybe), waitlist position (if capacity is reached), and check-in status. Supports manual RSVP add, edit, removal, waitlist promotion, and bulk export. RSVP submissions also flow in from the public-site RSVP form, gated by the per-event RSVP-required flag.
Export RSVP roster
Produces a CSV of RSVPs for an event. Columns: name, email, party size, response, RSVP timestamp, waitlist position, check-in status. Used for venue arrival lists, name badges, and post-event follow-up campaigns.
Manage venues
The venue sub-module — list, create, edit, soft delete, restore venue records. Each venue carries name, address, map coordinates, capacity, accessibility metadata, contact phone, and contact email. Editing a venue updates every active event attached to it. Deleting a venue requires that no active events reference it — the surface returns a structured rejection naming the events that block the delete.
Regenerate calendar feed
The Events module publishes an iCalendar feed (.ics) per public listing. Subscribers attach the feed URL to their external calendar (Google Calendar, Outlook, Apple Calendar) and receive automatic updates as events are added, edited, or cancelled. The regenerate action forces a fresh feed build; under normal operation the feed regenerates on every event write.
Data model
An event record carries the following fields. Field names below are the conceptual shape — the on-disk column names match closely but are not contractually stable across releases.
| Field | Type | Notes |
|---|---|---|
id | integer | Primary key. Stable across edits. |
title | string | Display name. |
slug | string | URL segment under /events/. Unique across active events. |
description | text | Rich-text body. Markdown subset supported. |
start_at | timestamp | Event start, in the site's primary time zone. |
end_at | timestamp | Event end. Must be after start_at. |
timezone | string | IANA time zone identifier. Defaults to site primary. |
venue_id | integer | Foreign key to a venue record. Null when remote or TBD. |
is_remote | boolean | True for online-only events. |
remote_url | string | Optional. The link participants use to join. |
capacity | integer | Optional. Triggers waitlist behavior when reached. |
rsvp_required | boolean | When true, the public listing requires an RSVP submission. |
ticket_product_id | integer | Optional. Foreign key to a product record when the event is paid. |
cover_image_id | integer | References a Media record. |
hosted_by | string | Optional. Attribution displayed on the listing. |
recurrence_rule | string | RRULE expression. Null for one-off. |
series_root_id | integer | Foreign key to the originating series template. Null for one-off or for the template itself. |
is_detached_from_series | boolean | True when this occurrence has been individually edited. |
status | enum | draft, active, cancelled, trash. |
seo_meta | JSON | Title, description, OG image for the event detail page. |
created_at | timestamp | Immutable. |
updated_at | timestamp | Touched on save. |
| Field | Type | Notes |
|---|---|---|
id | integer | Primary key. |
event_id | integer | Foreign key to the event. |
attendee_name | string | Display name. |
attendee_email | string | Unique per event. Used for confirmation and reminder mail. |
party_size | integer | Number of attendees included in the RSVP. Defaults to 1. |
response | enum | yes, no, maybe. |
waitlist_position | integer | Null until capacity is reached, then incremented. |
checked_in_at | timestamp | Set on arrival check-in. Null until then. |
submitted_at | timestamp | Submit time. |
| Field | Type | Notes |
|---|---|---|
id | integer | Primary key. |
name | string | Display name. |
address | string | Single-line postal address. |
latitude / longitude | decimal | Optional. Used for map rendering on the listing. |
capacity | integer | Optional. Default capacity for events at this venue. |
accessibility | JSON | Wheelchair access, hearing-loop, parking, etc. |
contact_phone | string | Optional. |
contact_email | string | Optional. |
status | enum | active, trash. |
status = trash is the soft-deleted state for both events and venues. Trashed records retain their RSVPs and their definition. Permanent delete is administrator-only and requires that no future occurrences reference the record.Recurrence expansion. A series template generates occurrence records on a rolling 90-day window. The expansion job is idempotent — re-running it does not duplicate already-created occurrences. Series edits before an occurrence is materialized propagate to the next-generated occurrences; series edits after materialization prompt the operator for "this occurrence / this and future / entire series".
RSVP uniqueness. One email may RSVP to an event exactly once. Re-submitting the same email updates the existing RSVP rather than creating a duplicate. Party size, response, and attendee name can change; the original submitted_at timestamp is preserved.
SERIES TEMPLATE MATERIALIZED OCCURRENCES("every Tue 15:00, 8 weeks")┌─────────────────────────┐│ recurrence_rule = RRULE │ ──────► OCC 1 May 23 15:00│ series_root_id = self │ ──────► OCC 2 May 30 15:00│ start, end, venue, etc │ ──────► OCC 3 Jun 6 15:00└─────────────────────────┘ ──────► OCC 4 Jun 13 15:00...on series edit:├─ "this occurrence only" → detach + edit OCC├─ "this and future" → edit OCC + roll forward└─ "entire series" → rewrite template + un-detached occsPUBLIC RSVP SUBMIT│▼per-event rsvp_required check│▼capacity check├─ under cap → RSVP row, response = yes└─ at cap → RSVP row, waitlist_position assigned│▼confirmation email (Email module)│▼reminder email scheduled(24h before start_at)Permissions
Access to the Events surface is gated at two layers.
Layer 1 — admin gate. Every action under SG-Admin passes through the standard admin access check at request entry. Unauthenticated requests never reach the Events surface. The public-site RSVP submit entry point bypasses this gate but enforces capacity and uniqueness checks inside the module itself.
Layer 2 — per-action capability. Within SG-Admin, each Events action checks a capability on the calling operator's role. The default role configuration ships with three roles — Administrator, Editor, Viewer — and an Events Coordinator role is a common custom addition. The capability map is:
| Capability | Administrator | Editor | Coordinator | Viewer |
|---|---|---|---|---|
| List events | ✔ | ✔ | ✔ | ✔ |
| Create event | ✔ | ✔ | ✔ | — |
| Edit event | ✔ | ✔ | ✔ | — |
| Duplicate | ✔ | ✔ | ✔ | — |
| Cancel | ✔ | ✔ | ✔ | — |
| Soft delete | ✔ | ✔ | — | — |
| Restore | ✔ | ✔ | — | — |
| Permanent delete | ✔ | — | — | — |
| Manage RSVPs | ✔ | ✔ | ✔ | — |
| Export RSVP roster | ✔ | ✔ | ✔ | — |
| Manage venues | ✔ | ✔ | — | — |
| Regenerate calendar feed | ✔ | ✔ | — | — |
Self-protection rules. An event cannot be soft-deleted if it has RSVPs scheduled within the next 24 hours — the surface returns a structured rejection prompting the operator to cancel rather than delete, which triggers the cancellation-notification path. A venue cannot be deleted while any active event references it. Series templates cannot be deleted while occurrences in the future window reference them — the template detaches the future occurrences first or rejects.
Audit. Every write — create, edit, duplicate, cancel, soft delete, restore, permanent delete, RSVP add, RSVP edit, venue change, feed regeneration — emits an Activity Log entry. The log records the acting operator, the event or venue, and the change shape (field-level diff for edits, occurrence range for series edits, count summary for bulk RSVP). Public-side RSVP submissions are not in the Activity Log — the RSVP roster itself is the audit surface for submissions.
REQUEST → /sg-admin/events/...│▼┌────────────────────────┐│ Admin gate │ unauth → reject└──────────┬─────────────┘│ authed▼┌────────────────────────┐│ Capability check │ role lacks cap → reject│ (per-action) │ (custom roles override defaults)└──────────┬─────────────┘│ allowed▼┌────────────────────────┐│ Self-protection rules │ RSVPs-within-24h / venue-in-use /│ │ series-has-future-occs → reject└──────────┬─────────────┘│ passes▼write executes│▼Activity Log entry│▼Public RSVP submissionsbypass Activity Log; RSVProster is the audit surface.Related references
- Pages — Reference. The events archive page and the per-event detail page render through the Pages module. Slug collisions are validated at save time.
- Posts — Reference. Posts about an event can reference the event record via shortcode; reciprocal links surface on the event detail page.
- Forms — Reference. Custom event-RSVP forms can replace the default RSVP form. Field mappings are configured on the event record.
- Users — Reference. Per-action capability checks resolve against Users. Operator attribution on event writes references user IDs.
- Email — Reference. RSVP confirmation, reminder, and cancellation templates live in the Email module.
- Commerce — Reference. Paid events link to product records. Ticket purchase flows through the Orders module.
- Settings — Reference. Time zone defaults, recurrence-expansion window, RSVP notification policy, and calendar-feed URL configuration live in Settings.
- Media — Reference. Cover images and OG images reference Media records.
/docs/events.