Signature
apply_filters( 'mam_specials_get_post_lat', mixed $lat, int $parent );
| Parameter | Type | Description |
|---|---|---|
$lat |
mixed | The latitude resolved by reading lat meta from the parent listing. May be a float, a numeric string, an empty string, or false. |
$parent |
int | The parent listing’s post ID — the post the special offer’s special-offer-parent meta points at. |
Returns: mixed — the latitude to use. Coerced to float by distance_between(). You must return it.
Purpose
Provides a per-parent override for the latitude used when computing whether an offer is “near” the requesting device. The plugin always sources offer coordinates from the offer’s parent listing, never from the offer itself, because offers don’t have their own location — they live where the venue lives. By default the parent’s coordinates come from lat post meta, which is GeoDirectory’s standard storage location.
This filter exists because not every parent post stores its coordinates that way. WooCommerce products don’t have a lat meta. Custom post types built on a different geo plugin may use different keys. And some apps want to relocate an offer’s apparent position (e.g., for a pop-up at a different venue than the parent).
For every read, the plugin calls a paired hook — mam_specials_get_post_lon — for longitude. They run side by side; treat them as one logical override.
When it runs
Twice per offer per request:
- Inside
mam_special_offers::get_data_for_app()(the nearby-offers feed). For every published offer, the parent’slatis read, filtered, and used to compute the device-to-offer distance. The result decides whether the offer is included in the response. - Inside
mam_special_offers::get_post_content()(the per-offer detail builder). The same value is filtered again and stored as the offer’slatfield in the JSON payload.
Source pattern:
$parent = get_post_meta( $post->ID, 'special-offer-parent', true );
$lat = apply_filters( 'mam_specials_get_post_lat', get_post_meta( $parent, 'lat', true ), $parent );
$lon = apply_filters( 'mam_specials_get_post_lon', get_post_meta( $parent, 'lon', true ), $parent );
The filter is consulted on the nearby-offers list builder and on each offer’s detail JSON. Returning different values across the two paths is technically allowed but will produce confusing UX (offer appears nearby, but its detail screen places it elsewhere).
Default behavior
mam_specials_get_post_lat → get_post_meta( $parent, 'lat', true )
If the parent has no lat meta, the filter receives an empty string. floatval('') is 0.0, which puts the offer “off the coast of West Africa” for distance purposes. Any positive request radius will still include such offers if $req_lat and $req_lon are also zero — see Hook: mam_specials_get_post_radius for the request-side gotcha.
Examples
Source coordinates from WooCommerce product meta
A product-driven app where product posts store coordinates as _product_lat / _product_lon:
add_filter( 'mam_specials_get_post_lat', 'my_app_product_lat', 10, 2 );
add_filter( 'mam_specials_get_post_lon', 'my_app_product_lon', 10, 2 );
function my_app_product_lat( $lat, $parent ) {
if ( 'product' !== get_post_type( $parent ) ) {
return $lat;
}
return get_post_meta( $parent, '_product_lat', true );
}
function my_app_product_lon( $lon, $parent ) {
if ( 'product' !== get_post_type( $parent ) ) {
return $lon;
}
return get_post_meta( $parent, '_product_lon', true );
}
Relocate an offer to a pop-up venue
Sometimes an offer’s parent venue isn’t where the offer is actually redeemable — a brewery-tied pop-up at a partner restaurant, for example. Store the override on the offer:
add_filter( 'mam_specials_get_post_lat', 'my_app_popup_lat', 10, 2 );
function my_app_popup_lat( $lat, $parent ) {
// The 'parent' arg is the listing, but we want to peek at the offer.
// Look up the offer the plugin is currently processing — but this filter
// doesn't pass it. So store the override on the parent instead.
$popup_lat = get_post_meta( $parent, '_specials_popup_lat', true );
return $popup_lat ?: $lat;
}
If you need per-offer overrides, store them on the parent indexed by offer ID, or on the offer with a callback that reads the global post inside the filter — but the latter is fragile.
Synthesize coordinates from a city name
If your data model stores city names rather than lat/lon on parent posts, geocode lazily and cache:
add_filter( 'mam_specials_get_post_lat', 'my_app_city_lat', 10, 2 );
function my_app_city_lat( $lat, $parent ) {
if ( $lat ) {
return $lat;
}
$city = get_post_meta( $parent, 'city', true );
if ( ! $city ) {
return 0;
}
$coords = my_app_geocode_city_cached( $city );
return $coords['lat'] ?? 0;
}
Cache the geocode lookup. The filter runs twice per offer per request.
Gotchas
- Companion hook is required. Overriding
mam_specials_get_post_latwithout overridingmam_specials_get_post_lonwill produce an “offer with right latitude, wrong longitude” — distance calculations will be nonsense. Always pair the two filters. $parentmay be a string or integer. It comes fromget_post_meta(), which returns the stored value as-is. The plugin doesn’t cast before passing. If you===compare against anint, you may miss matches.- No fallback to the offer’s own coordinates. Even though the offer JSON has
_range_lat/_range_lonon it, those are only read insideget_post_content()after the parent-derivedlatis set. Returning0from this filter will mean the distance check fails — the_range_*fields aren’t a fallback path. - Runs on every offer on every nearby-offers request. A naive lookup that hits the database for every parent post will cost N queries per request. Cache in object cache or a request-scoped static.
- Returning a value that isn’t numeric breaks the distance math.
floatval()is called downstream; non-numeric strings become0.0, masking the source of the bug. Return a number or a numeric string.
Verification
This article was last verified against:
- Plugin:
mam-special-offersv2.1 - Source:
mam-special-offers/includes/content-class-special-offers.php(get_data_for_app,get_post_content)
Re-verify whenever the parent-coordinate source meta key (lat) changes, the companion hook (mam_specials_get_post_lon) is renamed or removed, the parent linkage meta key (special-offer-parent) changes, or the distance comparison switches to a different reference point than $_REQUEST['lat'] / $_REQUEST['lon'].
Related articles
- Plugin: mam-special-offers
- Hook: mam_specials_get_post_radius
- Hook: mam_special_offers_deals_allowed
- Hook: mam_special_offers_skip_tab_bar_button
Metadata
| Field | Value |
|---|---|
| Article type | Hook Reference |
| Plugin slug | mam-special-offers |
| Applies to plugin version | 2.1+ |
| Category | Extending MAM Suite |
| Hook type | filter |
| Audience | PHP developer |
| Last verified | 2026-05-01 |
