Content type: GeoDirectory list and map

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 (and selected_category > 0).
  • The current user is not an admin, the listing is not publish, and the current user is not the listing’s post_author.
  • Hook: mam_geodirectory_skip_record returns true for 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 for geofilter_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_type or the synthetic content-source value. The class does not expose vc_type to 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 to 999999. A non-admin requesting that category gets the geofiltered standard list.
  • Off-directory uses the same query as list. The offDirectory rendering 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_geodirectory is a class_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-geodirectory v2.1.5
  • Source: content-classes/local-app-geodirectory-v2-class.php (content type registrations and get_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.


  • 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
Contents

    Need Support?

    Can’t find the answer you’re looking for? Don’t worry we’re here to help!