Mobile listing data shape

Summary

Every listing returned by mam_geodirectory_content::get_data_for_app() (alias local_app_geodirectory) is an associative array with the fields below. Some are pulled directly from the GD detail table, some are renamed for the mobile contract, and some are derived during the per-listing finalisers.

These keys are part of the frozen mobile contract. Renaming them will break deployed apps.


Where it appears

In every response from a GeoDirectory* content type:

  • The directory list and map content types return arrays of these objects.
  • The off-directory content type returns the same shape.
  • The calendar content type returns the same shape filtered to gd_event posts.
  • The detail screen for a single listing returns one of these objects (selected by the single_listing parameter).

The listing array is also fed back into:


Core identifiers (renamed from GD fields)

Key Type Source Notes
id int post_id Renamed for the mobile contract.
lat string/float latitude Renamed.
lon string/float longitude Renamed.
title string post_title after stripslashes() and get_the_title() Used for sort and search index.
post_type string get_post_type($post_id) One of the registered GD post types (e.g., gd_place, gd_event).
modified string post_modified Renamed.
rating string constant '0' The plugin does not produce real ratings; it pins this to 0.
raw_business_hours array business_hours Stored before the formatted-string version is built.

After renaming, the original keys (post_id, latitude, longitude, post_modified) are unset.


Derived strings

Key Type Built in Notes
url string finalize_listing_base_data() get_permalink($post_id), escaped.
website string Same esc_url_raw() of the listing’s website field. For events with ticket_url, replaced with the ticket URL (forced HTTPS).
region string Same Two-letter US/Canada abbreviation via convert_state(). District of ColumbiaDC.
state string Same Mirrors region when non-empty.
city_state_zip string Same '{city}, {region} {zip}'.
zip string Same ' ' (single space) when empty, to make detail rendering predictable.
post_date int Same UTC Unix timestamp via get_post_time('U', true, $id).
hours_one_line string Same business_hours_for_app from GD, or two spaces when empty.
searchIndex string finalize_listing_content() '{title} - {post_content}' — the app’s full-text search index.
subcategories string[] finalize_listing_categories() Names of every term and parent term assigned, plus 'My Venues' for owner/manager/staff. HTML entities are decoded.
content string finalize_listing_content() post_content after mam_localize_content and shortcode stripping. Set to ' ' when too short.
post_content, post_excerpt string Same Raw equivalents.

Owner-aware fields

Key Type Notes
can_delete 'yes' / absent Set to 'yes' for admin viewers.
can_delete_from_server 'yes' / absent Same.
contact_name string Pulled from contact_name post meta when present.
claim_status 'claimed' / 'unclaimed' / absent Set when the GeoDir Claim plugin is active and the listing supports claiming.
can_claim 'yes' / 'no' / absent Inverse of claim_status.

Marker / map fields

Built in finalize_marker_info():

Key Type Notes
marker_pin URL Custom marker JSON’s icon, or the term’s ct_cat_icon, or the GD default marker. SVGs are converted to a stub PNG (images/default.png).
marker_pin_aspect string height/width of the marker image, computed from attachment metadata.
marker_category '100' (constant) Used by the app to group markers.
market_extension string File extension of the marker image (note the spelling — frozen).
category_icon_url URL Term-level icon.
ct_cat_icon URL Category icon used in lists; SVG-converted.

When marker_pin is shorter than 10 characters (i.e., empty/garbage), the marker keys are unset entirely so the app falls back to its default pin.


Image fields

Built in finalize_listing_images() (and seeded by migrate_images()):

Key Type Notes
image string Sanitized filename.
imageurl URL Featured image URL. Narrow no-break space () characters are URL-encoded to %E2%80%AF.
image_id int Attachment post ID, or ' ' when not resolvable.
extension string File extension.
img_width, img_height string Pixel dimensions from attachment metadata.
imageSizeFactor, imageurl_aspect string Aspect ratios.
featuredRespectAspectRatio 'yes' When set, the app uses the natural aspect.
photo_array array Additional images; suppressed when mam_gd_hide_photo_array === 'yes'. Each entry is {src, aspect}.

When the listing has no featured image, the entries from static_placeholder (built from the local-app-images-placeholder option) are merged in.


Social platform fields

Each registered social platform key (from mam_social_platform_ids filter on mam-main) is added to the listing only when:

  1. The listing’s GD detail table actually has a column with that key (cached via gd_custom_field_exists).
  2. geodir_get_post_meta($id, $key) returns a non-empty value.

See Listing detail content sections — social_media for how these are rendered. Hook: mam_gd_social_icons_only lets you suppress text labels per listing.


Event-only extensions

When post_type === 'gd_event', finalize_event_listing() populates:

Key Type Notes
event_data array Set during processing then unset before the listing is returned.
event_records, activities array Always seeded with sentinel values.
event_registration mixed Pulled from geodir_eventregistration.
start_end_dates string 'Date: Aug 12' or 'Dates: Aug 12 - Aug 14 9:00am to 5:00pm'.
start_end_times string 'Time: All Day' or 'Time: 9:00am to 5:00pm' for recurring events.
start_date, sort_date string Used to sort events.
end_date int Unix timestamp of {end_date} 23:59:59.
event_start_stamp, event_end_stamp int Same as start_date/end_date, exposed for UI use.
dateList string[] Dates the event recurs on.
venue string The linked venue’s title (when present in cp_link_posts).
venue_id int The venue’s post ID.
event_ids int[] (For non-event venue listings) the IDs of events linked to this listing.
content_type 'web' Set when mam_gd_open_web_on_event_card option is 'yes', telling the app to open the ticket URL in a web view.

Past events (end date in the past) are dropped at this stage.


Sort fields

Key Type Notes
distance float Haversine miles from the request’s lat/lon to the listing. Only populated when geofiltering is active.

Cache marker

Key Type Notes
is_cached 'yes' / absent Set transiently when populating the per-request cache; unset before the listing is returned to the app.

Tab/finalise fields (transient)

These exist only between the per-listing finaliser and the final return. Don’t depend on them in mam_geodirectory_final_listings:

  • tab_type, tab_location — set so mam_tab_manager can decide which tab bar to attach. Unset after.
  • isCached — used during cache-hit replay.

Common recipes

  • Add a custom field to every listing. Hook Hook: mam_geodirectory_final_listings and walk the array, or add a post-meta key on save that the GD detail table picks up. Anything in the detail table is exposed automatically (under its column name).
  • Override coordinates. Currently only available via the special-offers integration (mam_specials_get_post_lat/_lon); for the directory itself, write to lat/lon post meta and the GD save pipeline updates the detail table.
  • Drop one listing. Use Hook: mam_geodirectory_skip_record — the listing array is short-circuited before any finalisers run.
  • Replace the whole list. Use Hook: mam_geodirectory_explcit_listings (note the typo in the name).

Gotchas

  • Empty strings are stripped. clean_empty_strings() removes any string key whose value is ''. Booleans and arrays are untouched. If your code relies on a key always being present, set it to a single space or a default array value.
  • marker_pin SVGs are replaced with a default PNG. The plugin’s svg_to_png() does not currently render SVG → PNG; it returns a stub default image. SVG markers will not appear in the app.
  • region may already be a 2-letter abbreviation. The convert_state helper falls through to strtoupper($state) for two-character inputs. If your data is mixed, the value is normalised either way.
  • Narrow no-break space in image URLs. The unicode (NARROW NO-BREAK SPACE) sometimes appears in WordPress image filenames. The plugin pre-encodes it to %E2%80%AF. Don’t double-encode downstream.
  • gd_custom_field_exists caches per request. Adding a column at runtime won’t be picked up until the next request.

Verification

This article was last verified against:

  • Plugin: mam-geodirectory v2.1.5
  • Source: content-classes/local-app-geodirectory-v2-class.phpget_data_for_app() and helpers

Re-verify whenever the per-listing finaliser methods (finalize_listing_*) are renamed or restructured, the field-renaming step in get_directory_data() changes, the SVG-to-PNG conversion is implemented for real, or new content types are added that bypass these finalisers.


  • Plugin: mam-geodirectory
  • Content type: GeoDirectory list and map
  • Listing detail content sections
  • Listing tab bar buttons
  • Hook: mam_geodirectory_final_listings
  • Hook: mam_geodirectory_skip_record
  • Hook: mam_geodirectory_explcit_listings
  • Hook: mam_gd_date_format
  • Hook: mam_gd_social_icons_only
  • Hook: mam_gd_events_exclude_from_map

Metadata

Field Value
Article type JSON Key Reference
Plugin slug mam-geodirectory
Applies to plugin version 2.1.5+
Category App Settings Reference
Audience PHP developer
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!