The idea in one sentence
Favorites is a per-user list of saved items. The list itself is just one screen in the app — but the items that can go onto it, and the actual record of who saved what, live out in the individual content plugins, not in some central “favorites” table.
That split is the one thing worth understanding about Favorites, because it explains almost everything else: which content types can be favorited, why the same star can mean different things from screen to screen, and where to look when a favorite seems to “disappear.”
Why it’s built this way
MAM Suite is built from content plugins — a directory plugin, a special-offers plugin, an events plugin, and so on — and each one already owns its own content type, its own data, and its own sense of what a user might want to save.
If Favorites tried to keep a master list of its own, it would need to understand the inner workings of every plugin in the suite. So instead, the platform flips the relationship around:
mam-mainowns the Favorites screen — the saved-items list view, the empty-state message, and the “remove all” behavior.- Each content plugin owns its own favorites data — it decides whether its content type can be favorited, persists each user’s saved items in its own storage, and contributes those items to the list.
The upshot: “what’s favoritable” isn’t a setting you flip in one place. It’s a capability each content plugin either implements or doesn’t — a content type is favoritable exactly when the plugin behind it has wired up the favorites toggle and the persistence to back it.
What a user can actually favorite
Because favoritability lives with each plugin, the honest answer is: it depends on which content plugins are installed and which of them have opted in.
The clearest example in practice today is the directory plugin (mam-geodirectory). It makes its listings favoritable — a star (or equivalent control) shows up on each listing row, and tapping it adds or removes that listing from the user’s saved items.
Other content plugins can follow the same pattern whenever they choose to participate — a special-offers plugin, for instance, can make its promotions favoritable using that same mechanism. The platform hands every plugin the shared plumbing (the toggle event and the list screen); it’s up to each one to decide whether to plug into it.
So when you’re asking “can users favorite X?”, what you’re really asking is “does the plugin behind X implement favorites?” If you’re not sure for a given content type, check that plugin’s Plugin Reference article to confirm it.
How an item gets onto a user’s list
Two moments make up that lifecycle, and each one involves a different piece of the system.
1. The toggle (saving or unsaving an item)
When a user taps the favorite control on a row, the app sends that toggle back to the server, where the content plugin that owns the item picks it up:
- It records the change in its own per-user storage. For the directory plugin this is a user-meta entry (
gd_user_favourite_post) that holds the list of post IDs that user has saved, plus a matching per-listing record of which users favorited it. - It then fires an action so other code can react. The platform exposes a generic toggle action (
mam_manage_favorites) for sibling plugins to subscribe to, and individual plugins may also fire their own (the directory plugin firesmam_gd_manage_favoritesafter it has finished updating storage).
The toggle is immediate and synchronous — there’s no pending state, no “undo.” The moment it’s recorded, it’s saved.
One gating detail worth knowing: the app only reports a toggle when the content’s own data tells it to. A flag in the mobile payload (report_favorites) is what turns toggle-reporting on. If a content type doesn’t set that flag, tapping the control never reaches the server, so nothing gets saved — which is part of why favoritability is a per-plugin capability rather than one global switch.
2. Populating the list (showing saved items back to the user)
The Favorites screen doesn’t hold its own copy of the list. Instead, every time the app fetches fresh data, the content plugins inject the current user’s saved items into the mobile payload — the directory plugin, for instance, reads that user’s saved post IDs from its user-meta and writes them into the payload as a favorites array.
So the list a user sees is assembled at request time, built from whatever the participating plugins contribute for that specific signed-in user. Two different users get two different lists from the same app, because each plugin is reading that user’s own storage.
A small detail that carries real weight: the favorites list is delivered as an array of strings, not integers — older mobile clients reject numeric IDs. You’ll never touch this yourself, but it’s why the developer-facing references describe the contract that way.
Where Favorites shows up in the app
Favorites shows up in two related places.
The Favorites screen. This is the saved-items list itself, rendered by the platform’s Favorites content class (local_app_favorites in mam-main) — essentially a navigation destination that displays the assembled list. Handy detail: the content class needs no configuration of its own. Its setup form literally says “No settings required,” because all the real work happens over in the sibling plugins and the shared list view. You place it like any other button or tab, in Mobile App Manager → App Setup.
The favorite control on individual rows. Wherever a favoritable content type is listed — directory listing rows, for example — the per-row star or toggle is what feeds the list. That control comes from the owning content plugin, not from the Favorites screen itself.
A couple of presentation details are yours to adjust, right on the Favorites button itself:
- A “remove all favorites” affordance, which can be hidden via the per-button Hide remove all favorites? setting (
hide_remove_all_favorites). - Standard per-button styling (colors, icon).
Both come from the standard App Setup button settings; the Favorites content class itself contributes nothing extra. The hide_remove_all_favorites choice also mirrors into the mobile payload as a flag, but the App Setup button is where you go to configure it.
When a user hasn’t saved anything yet, the screen shows a built-in empty state — that message comes from the list view’s own rendering, not from anything you can edit as an admin.
How the pieces connect
Here’s how a single favorite flows through the whole system, start to finish:
- A content plugin marks its content type as favoritable, telling the app to report toggles via the
report_favoritesflag. - The user taps the favorite control on a row, and the app reports that toggle back.
- The owning plugin records it in its own per-user storage, then fires its toggle action.
- On the next data fetch, that plugin injects the user’s saved IDs into the
favoritespayload. - The platform’s Favorites screen renders that assembled list — or its built-in empty state if nothing’s been saved — honoring the “remove all” setting from the button.
mam-main is the stage; the content plugins are the actors. The Favorites screen is deliberately thin so that any plugin can participate without the platform needing to know its internals.
Practical implications for admins
- “Is X favoritable?” is really a plugin question. Check the Plugin Reference for whichever plugin provides that content type — the Favorites screen can only display what a plugin has opted to make saveable.
- A missing favorite usually points to storage, not the screen. Since the list gets assembled from each plugin’s per-user storage, an item that vanishes is almost always a storage or contribution issue in the owning plugin — not a problem with the Favorites screen itself.
- You configure presentation, not membership. The Favorites button lets you hide “remove all” and style the screen, but it won’t let you add or remove what’s eligible to be favorited — that call belongs to the owning plugin.
- The list is per-user and built fresh every time. There’s no shared list to “reset” centrally — each user’s list comes from their own saved records, rebuilt each time the app loads data.
Related
- Content class: Favorites (Screen Reference) — the
local_app_favoritesrenderer and its JSON contract - Hook: mam_manage_favorites — the platform toggle action sibling plugins subscribe to
- Hook: mam_gd_manage_favorites — the directory plugin’s post-toggle action
- Plugin: mam-geodirectory — the worked example of a favoritable content type
- Mobile JSON shape — where
favorites,report_favorites, andhide_remove_all_favoriteslive in the payload
