The concept: one content surface, many plugins enriching it
MAM Suite is built the way WooCommerce is: a small core (mam-main), surrounded by feature plugins that each do one job. None of them is a monolith, and none of them requires another feature plugin to work. Instead, when two happen to be active on your site at the same time, they find each other — and one enriches the other.
Here’s why that matters: it’s how your app gains depth without anyone writing a line of code. A directory of venues is useful on its own. But the moment you also activate Special Offers, those same venues start showing deals. Activate Chat Manager and the same venues pick up a Message button. Activate Reviews and they gain a star rating and a review feed. The venue listing itself never changed — it just became a richer surface because other plugins layered onto it.
Under the hood, this runs on WordPress filters and actions, used as a contract between plugins. One plugin owns a hook — it fires the hook and documents what shape the data takes. Another plugin subscribes to that hook to contribute data or change a decision, and the owner never has to know who, if anyone, is listening. That’s why every plugin overview in this codex has a Works with row rather than a hard dependency list: the relationships are optional, additive, and worked out at runtime.
The rest of this article maps those relationships out. Keep one pattern in mind as you read: the directory is the hub, and the other plugins are spokes that enrich it. Most of the wiring lives in mam-geodirectory — the largest of the no-code plugins, and the one that most often produces the content the others decorate.
The core and the spokes
Two layers are worth telling apart here.
mam-main is the platform core. Every feature plugin depends on it. It owns the phone-data pipeline (the JSON payload the mobile app fetches), the tab bar, the content-section system, the form pipeline, the AJAX router, and push notifications. The hooks you see referenced everywhere — mam_get_phone_data_before_send, mam_main_add_tab_bar_item_*, mam_content_section_*, mam_tab_manager — are all owned by mam-main. If mam-main is missing, a feature plugin quietly exits in its constructor — there’s simply nothing for it to attach to.
The feature plugins are the spokes. Each one depends on mam-main and nothing else. Every relationship between feature plugins is optional:
| Plugin | One-line job | Enriches / is enriched by |
|---|---|---|
mam-geodirectory |
Turns GeoDirectory listings and events into mobile content surfaces | The hub — feeds geofilters, offers, chat, reviews, IAP, WooCommerce |
mam-geofilters |
City picker that filters app content by location and radius | Consumes cities from the directory |
mam-special-offers |
Time-bounded deals attached to listings/products | Consumes coordinates and per-package caps from the directory |
mam-chat-manager |
One-on-one, group, and support chat | Gets per-listing groups and a Chat button from the directory |
mam-reviews-manager |
Star ratings and reviews on any post | Registers review sections onto the directory’s detail screen |
mam-inapp-purchase-manager |
App Store / Google Play purchase gating | Lets the directory exempt owners/staff from the gate |
mam-gravity-forms-manager |
Bridges Gravity Forms into the in-app form pipeline | Backs in-app forms for the directory, offers, and contact form |
mam-contact-form |
A Contact Us form in the app | Optionally backed by the Gravity Forms bridge |
That asymmetry is deliberate. The directory is almost always the producer of content, and the other plugins are consumers that decorate it — which is why this article keeps circling back to mam-geodirectory.
How the directory feeds each surface
Below is that same set of integrations, walked through one at a time: what one plugin gives the other, and through which hook. In every case, the hook belongs to the receiving plugin, and the directory is the one subscribing to it. That direction is the key to reading the whole map: the directory never reaches into the other plugins — it answers questions the other plugins ask.
Directory → GeoFilters: the city list
mam-geofilters ships with a static built-in list of about 60 US cities for its location picker. When mam-geodirectory is also active, it subscribes to the mam_geofilter_list filter (owned by geofilters) and replaces that list with the distinct cities your directory actually has listings in. So the picker shows the cities your data actually covers, not a generic default.
The gating here is clean: the moment mam_geofilter_list picks up a subscriber, geofilters skips its default-list path entirely. There’s no merging the two — if you want your cities and the defaults together, you’ll need to add the defaults yourself. This is the simplest spoke in the map, and it’s fully automatic: activate both plugins, and the city list re-sources itself.
Directory → Special Offers: coordinates, caps, and button gating
When mam-special-offers is active, the directory steps in to answer three things on its behalf:
- Coordinates and radius. Offers need to know where their parent listing sits, so the “nearby offers” feed can work. The directory subscribes to
mam_specials_get_post_lat,mam_specials_get_post_lon, andmam_specials_get_post_radiusand returns each GD listing’s stored latitude/longitude (and an optional global radius override). For non-GD parents, special-offers falls back to its own resolution. - Per-package deal cap. A pricing package can include a
no_of_deals_includedcount. The directory translates that into the cap special-offers enforces on the “Edit Deals” button, viamam_special_offers_deals_allowed. - Tab bar gating. The directory hard-skips the “Edit Deals” button for anyone who is not the owner/manager/staff/admin of the listing, via
mam_special_offers_hard_skip_tab_bar_button, before special-offers even tries to build it.
This is the most layered spoke in the map: the directory supplies geography, business rules, and visibility logic that special-offers has no way to know on its own.
Directory → Chat Manager: per-listing groups and the Message button
When mam-chat-manager is active, the directory builds chat right into the listing detail screen. If someone viewing a venue passes the rules — the package’s “Chat With Venue” flag is on, they aren’t staff or the listing’s author, and it isn’t an admin-to-admin context — the directory creates (or reuses) a per-listing chat group and hands it off to chat-manager through the mam_add_chat_to_detail filter. Chat-manager takes it from there, injecting the Message button and the conversation routing into the payload.
The directory also keeps the group membership in sync: when a staff member or manager is accepted or removed, it adds or drops them from the listing’s chat group automatically. The actions driving this (mam_gd_staff_member_accepted / mam_gd_staff_member_removed) are subscribed to here but fired elsewhere — a good reminder that the producer/subscriber split doesn’t always line up the way you’d expect.
Directory → Reviews: review sections on the detail screen
When mam-reviews-manager is active, it registers its review content sections (an “Add a Review” form, a reviews header with the aggregate rating, and the reviews feed) specifically onto the directory’s content type — keyed on the local_app_geodirectory content-type id. The result: a GD listing’s detail screen gains a star summary and a review list.
Reviews-manager uses a provider model: it resolves a provider for whichever post is being reviewed and reads ratings and review data through it. That’s the indirection that lets reviews attach to directory listings (and other post types) without reviews-manager ever needing to know anything about GeoDirectory internals. The directory contributes the surface; reviews-manager contributes the rating data.
Directory → In-App Purchase Manager: exempting owners and staff
When mam-inapp-purchase-manager is active, it asks mam_iap_require_iap whether the current user should hit the purchase gate. The directory subscribes and answers “no” for users who are staff on any listing — so a venue owner is never locked out of their own venue for lack of a subscription. Users with a pending staff invite are likewise exempted on the launch where the invite form appears.
This spoke is purely a decision — the directory contributes an answer to a gate that IAP owns. There’s no UI involved here; it simply changes the answer to one yes/no question.
Directory ↔ WooCommerce: package purchases update listings
WooCommerce sits a bit outside the MAM plugin family, but it’s wired in the same way. When a customer buys a GeoDirectory pricing-package product, the MAM order pipeline fires mam_wc_successful_simple_product_order, and the directory subscribes to upgrade or downgrade every listing that customer owns to the new package, prorating the expiry date. IAP itself is backed by WooCommerce products too — so WooCommerce ends up as the billing substrate under both the website’s pricing-package flow and in-app purchases.
Reading the map: producer vs. subscriber
If you take away one rule from this whole article, make it this one for reasoning about any MAM integration:
- The plugin that fires a hook owns its name and shape. It is the producer. It defines a question or a slot.
- The plugin that subscribes answers the question or fills the slot. It is the consumer.
- The producer never depends on any particular consumer showing up. If nobody subscribes, the feature just falls back to its own default.
Applied to the spokes above: geofilters owns mam_geofilter_list and falls back to its built-in cities if nobody subscribes; special-offers owns the radius/lat/lon filters and falls back to its own resolution; IAP owns mam_iap_require_iap and gates normally if nobody overrides it. The directory is simply the busiest subscriber in the whole suite — which is why turning it on makes so many other plugins “light up.”
This is also why order of activation doesn’t matter, and why you can add or remove a plugin without breaking the others. Every integration is checked at runtime — usually with a class_exists or “is this other plugin active” guard — so a missing plugin just means a missing decoration, not an error.
Where this leaves you
- For admins: you build your app by activating plugins, not by wiring up connections between them yourself. Turn on the directory, then turn on whichever feature plugins you want layered onto it, and the wiring happens on its own. The handful of things you do configure — a package’s “Chat With Venue” flag, the deals-included count, the IAP-exempt toggle — are settings on the directory itself, and they govern how aggressively it enriches a surface.
- For developers: when you need to change how two plugins interact, find the hook the receiving plugin owns and either override the directory’s subscriber or add your own. You almost never edit a plugin to change an integration — you adjust a filter.
The integration-specific behavior summarized here is documented in full on the directory’s side, one article per spoke — start there when you need exact hook signatures, gating rules, and gotchas.
Related articles
- Plugin: mam-geodirectory — the hub, with the full list of hooks it owns and subscribes to
- Integration: GeoFilters — how the city list is re-sourced from your listings
- Integration: Special Offers — coordinates, per-package caps, and Edit Deals gating
- Integration: Chat Manager — per-listing chat groups and staff auto-enrolment
- Integration: In-App Purchase Manager — exempting owners and staff from the gate
- Integration: WooCommerce pricing packages — package purchases that rebase listings
- Plugin: mam-main — the platform core that owns the phone-data, tab bar, and content-section pipelines
