What you’ll build
By the end of this tutorial, you’ll have a working events app where an app user can:
- Browse upcoming events in a list, on a map, or on a calendar.
- Open an event and tap I’m Going to RSVP — recording their attendance and letting the venue know.
- Get a reminder push notification the day before (and again the day of) the event.
- Flash a QR confirmation code on their phone at the door, for staff to scan and check them in.
MAM Suite doesn’t have one single “events” plugin. Instead, you’ll assemble an events app from a handful of plugins that each own one piece of the flow. This tutorial walks you through the whole build, pointing to the deeper per-plugin recipes along the way.
| Capability | Provided by |
|---|---|
| Event content (dates, schedules, map, calendar) | MAM GeoDirectory + the third-party GeoDirectory and GeoDir Event Manager plugins |
| RSVP (“I’m Going”) + per-attendee QR confirmation | MAM Special Offers (RSVP-enabled offer attached to the event) |
| Reminders the day before / day of | GeoDirectory reservation-reminder notification types, dispatched through MAM Main |
| Push / email / in-app delivery | MAM Main notification system |
| Staff-facing QR for app downloads / scan-to-listing | MAM GeoDirectory Add QR Code form (optional) |
One more thing before you dive in: the two RSVP/QR mechanisms below come from two different plugins and produce different QR codes for different purposes. GeoDirectory events give you the content surface and reminders; the per-attendee RSVP plus check-in QR comes from attaching an RSVP-enabled special offer to the event. There’s no separate event-RSVP path — RSVP lives entirely in MAM Special Offers.
Before you start
You’ll need:
- A MAM Suite app project with mam-main active.
- MAM GeoDirectory active, plus the third-party GeoDirectory plugin and GeoDir Event Manager add-on. Without GeoDir Event Manager, the
gd_eventpost type and event schedules aren’t available. - MAM Special Offers active (for the RSVP + check-in QR step).
- The MAM Main notification system configured so push, email, and in-app messages can actually be dispatched.
- For staff QR codes (optional, Part 5): Branch deep linking configured via the
branch_app_idoption.
Here’s the catch: if any required plugin is missing, the corresponding MAM plugin quietly no-ops in its constructor — no error, events just won’t show up. Double-check all three GeoDirectory pieces are active before you go any further.
Part 1 — Create your events
Under the hood, events live in GeoDirectory’s gd_event post type. MAM GeoDirectory treats gd_event as its own event surface, separate from regular listings (gd_place), which is why events automatically pick up the calendar and event-card treatment.
- In WordPress, go to GeoDirectory → Add Event (the menu label comes from GeoDir Event Manager) and create an event.
- Give it a title, description, and a featured image — that image becomes the hero on the event’s card in the app.
- Set the event’s schedule (start date/time, end date/time, and any recurrence). MAM GeoDirectory reads upcoming schedules through the
mam_gd_get_event_scheduleproducer filter, which resolves them viaGeoDir_Event_Schedules::get_schedules($event_id, 'upcoming'). Only upcoming schedules are surfaced, so an event with only past dates won’t show. - Add a location for the event so it can appear on the map and in distance-aware lists.
- Publish.
Heads up: the event schedule filter is hard-coded to
'upcoming', so an event whose schedules are all in the past will disappear from the app — even though the post itself is still published.
Repeat this for each event you add. You don’t need to create them all right now — one is enough to test the full flow.
Part 2 — Show events in the app
Now let’s put those events in front of users. MAM GeoDirectory registers several content-type views for directory content — list, map, calendar, off-directory, and admin-approval. For an events app you’ll typically want a calendar or list view as a main tab, with an optional map alongside it.
- Go to Mobile App Manager → App Setup (the screen/tab builder).
- Add a screen backed by the GeoDirectory content type and choose the calendar or list presentation.
- (Optional) Add a second screen using the map presentation so users can find events near them. The default search radius is 25 miles; it’s overridable per app via the
tsl-setting-geofilter_radiusapp setting or per request with?radius=. - Build the event detail screen out of MAM content sections (event details, address, business hours, social media, post content). See Design the listing detail screen — events use the same content-section system as listings.
At this point users can already browse events, open one, and see its details. Next, let’s add the RSVP button.
Want finer control over which events appear and how their cards render? See the developer hooks
mam_geodirectory_event_card,mam_geodirectory_final_listings, andmam_gd_events_exclude_from_map.
Part 3 — Add RSVP (“I’m Going”) and the attendee QR code
This is the heart of the events flow: the RSVP button and the per-attendee QR confirmation both come from attaching an RSVP-enabled special offer to the event. The full mechanics are documented in Recipe: Enable RSVP for a special offer; what follows here is the events-app-specific summary.
RSVP is gated by a single meta key on the offer post: special-offer-has-rsvp. Once that’s non-empty, four things switch on:
- The detail screen shows an I’m Going check-in button; tapping it dispatches the
mam_check_inaction, passing the offer’s post ID in$_REQUEST['checkinloc']. - The plugin records each user’s RSVP state on the offer:
mam_so_is_going_{user_id}=yes, alongside a pairedmam_so_is_going_date_{user_id}that stores the date they signed up. - A notification fires on RSVP — as long as
special-offer-rsvp-emailis set to a registered WordPress user’s email, that venue user gets aspecial-offers-event-rsvpnotification (push + email + in-app), with{attendee_name}available to use in it. - The detail screen gains a Confirmation section with a QR code — it encodes a
wp_create_noncetoken unique to that event and user, and it’s the code staff scan at check-in.
To enable it:
- Attach a special offer to the event listing (see Recipe: Add a special offer to a listing) — this offer becomes your RSVP record-keeper.
- Turn on the RSVP flag for that offer:
update_post_meta( $offer_id, 'special-offer-has-rsvp', 'yes' );The plugin only checks whether this is non-empty;
'yes'is used here simply to match the plugin’s other conventions. - Point the venue notification at a registered WP user’s email:
update_post_meta( $offer_id, 'special-offer-rsvp-email', 'venue-owner@example.com' );If that email doesn’t match a
WP_User, the RSVP still gets recorded, but no notification fires — and nothing tells you it didn’t. Verify the match yourself withget_user_by( 'email', ... ). - (Optional) Set a seat count for an “Only N left!” display:
update_post_meta( $offer_id, 'special-offer-quantity', '20' );This number is informational only — it doesn’t enforce a cap. The plugin simply subtracts the count of existing
mam_so_is_going_*keys from it for display.
Heads up: there’s no native admin UI for these meta keys yet — you’ll set them programmatically (or via a custom meta box).
Test it: Open the app as a test user, go to the event, and tap I’m Going. The button should flip to a Cancel state, a Confirmation QR section should appear, and the venue email’s user should get the RSVP notification. Tap again and the RSVP clears.
Part 4 — Send reminders the day before and day of
MAM GeoDirectory ships reservation-reminder notification types you can use to nudge attendees ahead of their event. Two relevant slugs come in the GeoDirectory notification list:
| Slug | When | Replacement tokens |
|---|---|---|
geodirectory-pending-reservation-tomorrow |
Reminder for a booking starting tomorrow | {location_name}, {location_address}, {start_date}, {end_date} |
geodirectory-pending-reservation-today |
Reminder for a booking starting today | Same set |
To use them:
- Go to Mobile App Manager → Notifications, where you’ll find the GeoDirectory notification types grouped under the GeoDirectory source.
- Open
geodirectory-pending-reservation-tomorrowand write its template — push title, push body, email subject, email body — using the replacement tokens above. The plugin doesn’t generate any wording on its own; whatever you write here is the only text that goes out. - Do the same for
geodirectory-pending-reservation-todayif you want a same-day nudge. - Under the hood, notification slugs are dispatched via
do_action('mam_notification_send_message', $message), with$message['message_type']matching the slug and$message['replacements']filling in the token keys. MAM GeoDirectory registers these two reminder templates but ships no dispatcher for them — nothing in the plugin firesgeodirectory-pending-reservation-tomorrowor-todayon any schedule. Writing the template only makes it available; something else still has to actually send it.
Caveat: these reminder slugs are registered as notification templates only — MAM GeoDirectory doesn’t include a cron or booking hook that emits them, so writing a template alone won’t produce any reminders in testing. You’ll need a dispatcher (custom code, or a booking system that fires
mam_notification_send_messagewith the matchingmessage_type).
If you want a reminder that fires reliably off the RSVP list, a developer can enumerate attendees from the offer’s mam_so_is_going_* meta and dispatch a custom notification slug on a daily schedule — see Recipe: Enable RSVP for a special offer for the attendee-enumeration snippet. That’s the recommended path for an RSVP-style events app, since the built-in reservation-reminder slugs never fire on their own.
Part 5 — (Optional) Give staff a QR for downloads and scan-to-event
Separate from the per-attendee check-in QR, MAM GeoDirectory can show venue staff a QR code in the app’s left menu that customers scan to download the app or jump straight to the staff member’s listing — handy at an event table or entrance. Full steps are in Form: Add QR Code; here’s the short version:
- Build a Gravity Form with a single hidden field whose slug is
qrcode-field. - Wire its form ID under Mobile App Manager → Geodirectory → Settings → GeoDirectory: Add QR Code to DL the App.
- Add that form to the app’s left menu / drawer — the plugin finds it by
formidand injects the QR URL at request time. - Configure Branch (the
branch_app_idoption) so the plugin can mint a deep link. It caches the link per listing undermam_site_qrcode_{listing_id}.
The QR feature hides itself entirely when universal links aren’t set up (the mam_universal_link_enabled filter returns false) — so configure Branch first, or it won’t show up.
How the pieces fit together
Event content + map/calendar + reminders ──► MAM GeoDirectory (gd_event)
│ (GeoDir Event Manager schedules)
▼
Event detail screen ──► RSVP-enabled special offer attached to the event
│ │
│ ├─► "I'm Going" button → mam_check_in
│ ├─► per-attendee QR (wp_create_nonce) → check-in
│ └─► RSVP notification → venue email user
▼
Reminders (tomorrow / today) ──► geodirectory-pending-reservation-* slugs
▼
Delivery (push / email / in-app) ──► MAM Main notification system
Troubleshooting
- Events don’t appear at all. Make sure GeoDirectory, GeoDir Event Manager, and MAM GeoDirectory are all active, and confirm the event has at least one upcoming schedule — past-only events get filtered out.
- No “I’m Going” button. Check whether
special-offer-has-rsvpis non-empty on the offer attached to the event (get_post_meta( $offer_id, 'special-offer-has-rsvp', true )). - RSVP works but the venue gets no email. The recipient lookup happens by
WP_Useremail — a typo or an unregistered address sends nothing, silently. - QR confirmation doesn’t render. The QR only shows up after a successful RSVP — confirm the RSVP was actually recorded (
mam_so_is_going_{user_id}). - Reminders never arrive. The built-in
geodirectory-pending-reservation-tomorrow/-todayslugs are registered templates with no automatic dispatcher in MAM GeoDirectory — writing the template doesn’t schedule anything on its own. For reliable reminders, dispatch a custom slug off the RSVP list instead (see Part 4). If you’re wiring your own dispatcher, confirm it firesmam_notification_send_messagewith the matchingmessage_typeand that$message['replacements']fills in the tokens. - Cancelling an RSVP doesn’t un-send anything. There’s no cancellation notification path — a user who RSVPs and then cancels has already triggered the venue email.
Where to go next
- Recipe: Enable RSVP for a special offer — the full RSVP + QR mechanics, attendee enumeration, and gotchas.
- Recipe: Add a special offer to a listing — attaching the offer that backs the RSVP.
- Form: Add QR Code — the staff-facing download/scan QR.
- GeoDirectory notification types — all twelve GeoDirectory notification slugs and their tokens.
- Hook: mam_gd_get_event_schedule — reading upcoming event schedules in code.
- Design the listing detail screen — building the event detail screen from content sections.
- Plugin: mam-geodirectory and Plugin: mam-special-offers — the reference overviews for the two plugins this app is built on.
Verification (for reviewers)
This draft was grounded against:
mam-special-offers/user_docs/03-recipe-rsvp-offer.md— RSVP flag,mam_check_in, per-user meta,special-offers-event-rsvpnotification, QR nonce.mam-special-offers/user_docs/01-plugin-overview-mam-special-offers.md— RSVP surfacing, offer meta keys.mam-geodirectory/user_docs/01-plugin-overview-mam-geodirectory.md—gd_eventhandling, content types, radius, QR feature.mam-geodirectory/user_docs/06-notification-types.md—geodirectory-pending-reservation-tomorrow/-todayslugs and tokens.mam-geodirectory/user_docs/07n-hook-mam-gd-get-event-schedule.md— upcoming-schedule resolution.mam-geodirectory/user_docs/04g-form-add-qrcode.md— staff QR / Branch flow.
Re-verify (and tighten the flagged caveats) whenever: a dedicated event-RSVP path replaces the special-offer RSVP mechanism; the reservation-reminder dispatch trigger is documented or changed; an admin UI is added for the RSVP meta keys; or the mam_check_in / QR nonce contract changes.
