Primary responsibility
mam-geodirectory registers five entries into the global $local_app_content array, each one a content type the admin can pick when configuring a screen in the app builder. All five share the same content class — local_app_geodirectory (a class_alias of mam_geodirectory_content) — but expose different vc_type values, which the mobile app uses to choose a layout.
| Content type slug | content_type label |
vc_type |
Behavior |
|---|---|---|---|
GeoDirectory |
“GeoDirectory” | list |
Standard scrolling list of listings filtered by category and (optionally) by geofilter. |
GeoDirectory_admin_approvals |
“GeoDirectory – Admin Approvals” | list |
Same list, but restricted to pending listings; only visible to admins. |
GeoDirectory_offdir |
“GeoDirectory – Off Directory” | offDirectory |
Off-directory feed shape — used for non-geographic listings (the underlying class still drives the data). |
GeoDirectory_Map |
“GeoDirectory – Map View” | list_map |
Same listings, rendered as map markers. |
GeoDirectory_calendar |
“GeoDirectory Calendar” | calendar |
Events feed — uses get_events_only() to restrict to gd_event posts. |
All five are content-source-aware. The admin’s category picker (rendered by get_content_type_form()) shows each registered GD post type as a top-level option, the post type’s category terms as nested options, and a synthetic “Admin Approvals” option that maps to category id 999999.
What each surface returns
GeoDirectory (list)
The default surface. get_data_for_app() resolves the post type from the picked category, queries the appropriate {prefix}{post_type}_detail table, applies geofiltering when tsl_gd_map_manager_cities matches the request’s lat/lon, and runs the per-listing finalisers (categories, marker icons, images, social platforms, claim status, chat). Returns an alphabetically sorted (by title) or distance-sorted (when tsl-setting-directory_display_distance_from_user === 'yes') array of listing objects.
GeoDirectory_admin_approvals (admin-only)
A content surface that only shows up to administrators when category=999999 is requested. The class flips an internal is_admin_approval flag, disables geofilters, and filters the result down to rows with post_status === 'pending'. A nocat flag is added to each listing so the app suppresses category badges for the approval queue.
GeoDirectory_offdir
Returns the same listing data shape as the standard list, but the vc_type=offDirectory instructs the app to render an “off-directory” template. Useful for content surfaces where listings should appear without their map context.
GeoDirectory_Map
Identical data, vc_type=list_map. Each listing carries marker_pin, marker_pin_aspect, category_icon_url, lat, and lon. The mam_gd_events_exclude_from_map filter (see Hook: mam_gd_events_exclude_from_map) lets you suppress gd_event rows from the map even when the picked category is a gd_event taxonomy term.
GeoDirectory_calendar
get_events_only() forces the post type to gd_event and re-runs get_data_for_app(). The returned event rows are sorted by sort_date (a Unix timestamp parsed from the event’s start). The phone-data hook also injects a placeholder no_events.png image into the tab manager (no_image_manager()) when the calendar tab has no upcoming events, so the app can show a “no events” empty state.
Geofiltering and admin-approval together
Geofilters and admin-approval are mutually exclusive: when the request resolves to admin-approval mode (category=999999 and the user is an admin), use_geofilters is forced to false regardless of any matching city in tsl_gd_map_manager_cities. This is intentional — admins reviewing pending submissions need to see the whole queue, not just listings near their device.
Default sorting
| Mode | Sort key | Sort order |
|---|---|---|
tsl-setting-directory_display_distance_from_user === 'yes' AND geofilter active |
distance (Haversine miles) |
ascending |
| Otherwise | title (lower-cased, natural-flag) |
ascending |
gd_event only mode |
sort_date (timestamp) |
passed through local_app_sksort (mam-main frozen sorter) |
The class uses array_multisort with SORT_NATURAL | SORT_FLAG_CASE so titles like “Joe’s #2” sort intuitively.
Author/admin visibility filters
The should_include_listing() method drops a listing from the result before any finalisers run if any of these are true:
- The listing’s category does not match a numeric
selected_category(andselected_category > 0). - The current user is not an admin, the listing is not
publish, and the current user is not the listing’spost_author. - Hook: mam_geodirectory_skip_record returns
truefor the listing’s ID.
Pending listings owned by the current user are always shown to that user; admins always see pending listings in admin-approval mode.
JSON keys consumed
When admins pick a GeoDirectory content type for a screen, the app sends these request parameters back:
lat,lon— current device coordinates (for geofilter matching and distance sort).actual_lat,actual_lon— raw GPS, used by the geofilter list-builder upstream.radius— optional override; capped at 3000.city_name— picked city name (used by the phone-data hook forgeofilter_default_name).no_gps—'yes'when GPS is unavailable; triggers GeoIP fallback if installed.
Gotchas
- All five content types share one class. Modifying behavior (e.g., a custom finaliser) affects every surface unless you check
vc_typeor the synthetic content-source value. The class does not exposevc_typeto filter callbacks; use Hook: mam_geodirectory_explcit_listings if you need a fully alternate dataset. - Admin approvals require an admin user AND
category=999999. Picking the synthetic “Admin Approvals” option in the admin picker maps to999999. A non-admin requesting that category gets the geofiltered standard list. - Off-directory uses the same query as list. The
offDirectoryrendering happens entirely on the client; the backend pipeline is unchanged. - The map view shows events by default. Use Hook: mam_gd_events_exclude_from_map to suppress them.
- Class name vs. alias. The actual class is
mam_geodirectory_content;local_app_geodirectoryis aclass_alias. Both names work in code but the alias is the legacy name and what the registration array uses.
Verification
This article was last verified against:
- Plugin:
mam-geodirectoryv2.1.5 - Source:
content-classes/local-app-geodirectory-v2-class.php(content type registrations andget_data_for_app())
Re-verify whenever a $local_app_content registration is added/removed, vc_type values change, the admin-approval category id (999999) changes, or the sort logic in get_data_for_app() changes.
Related articles
- Plugin: mam-geodirectory
- Listing detail content sections
- Listing tab bar buttons
- Mobile listing data shape
- Integration: GeoFilters
- Hook: mam_geodirectory_explcit_listings
- Hook: mam_geodirectory_final_listings
- Hook: mam_geodirectory_skip_record
- Hook: mam_gd_events_exclude_from_map
Metadata
| Field | Value |
|---|---|
| Article type | Screen Reference |
| Plugin slug | mam-geodirectory |
| Applies to plugin version | 2.1.5+ |
| Category | App Settings Reference |
| Audience | WordPress admin |
| Last verified | 2026-05-01 |
