Signature
apply_filters( 'mam_specials_get_post_radius', int $radius );
| Parameter | Type | Description |
|---|---|---|
$radius |
int | Default search radius in miles. The plugin’s own caller passes 5. |
Returns: int — the radius in miles. You must return it.
Purpose
Sets the search radius used by the nearby-offers feed to decide which published special offers are close enough to the requesting device to appear. The plugin’s mam_special_offers::get_data_for_app() walks every published offer, resolves each offer’s parent-listing coordinates, and computes a great-circle distance from $_REQUEST['lat'] / $_REQUEST['lon']. Offers within $radius miles are returned; the rest are dropped.
The default of 5 miles is tight on purpose — it’s tuned for hyperlocal apps where you only want offers in the same neighborhood as the user. Any app serving a wider area will need to bump it.
This filter has no admin-side equivalent. Unlike mam-geofilters, the special-offers radius is not stored in role settings or a per-app option — it is purely code-driven.
When it runs
Inside mam_special_offers::get_data_for_app() (includes/content-class-special-offers.php), once per request:
$radius = apply_filters( 'mam_specials_get_post_radius', 5 );
foreach ( $posts as $post ) {
// ... resolve $lat / $lon for the offer's parent ...
if ( MAM_Input_Validator::is_null_island( $req_lat, $req_lon )
|| $this->distance_between( $req_lat, $req_lon, $lat, $lon ) < $radius ) {
$dir_details[] = $this->get_post_content( $post );
}
}
Note the MAM_Input_Validator::is_null_island() short-circuit: when the request supplies no usable GPS ($req_lat / $req_lon at (0, 0)), the distance test is skipped and every offer is returned regardless of the radius. The radius only filters when the device sends real coordinates.
The filter fires once per request, before the per-offer loop. It is not consulted on the listing-detail offers section (which only checks the offer’s parent linkage). It only affects the location-aware offers list.
Default behavior
mam_specials_get_post_radius → 5 (miles)
Offers whose parent listing has no resolvable coordinates resolve to (0, 0). Against a device sending real GPS, those offers compute a large distance and are filtered out — increasing the radius does not make them visible by accident. Against a device sending no GPS ($req_lat / $req_lon at (0, 0)), the MAM_Input_Validator::is_null_island() guard short-circuits the distance check and all published offers are returned regardless of radius — see the gotchas below.
Examples
Wider radius for a regional app
add_filter( 'mam_specials_get_post_radius', static fn () => 50 );
A constant override is fine — there’s only one decision per request.
Per-role radius
add_filter( 'mam_specials_get_post_radius', 'my_app_specials_radius' );
function my_app_specials_radius( $radius ) {
if ( current_user_can( 'premium_member' ) ) {
return 100;
}
return $radius;
}
Tied to the geofilters radius
If the same app uses mam-geofilters, you may want the special-offers feed to respect the user’s chosen geofilter radius rather than its own:
add_filter( 'mam_specials_get_post_radius', 'my_app_match_geofilter_radius' );
function my_app_match_geofilter_radius( $radius ) {
return (int) apply_filters( 'mam_geofilter_radius', $radius );
}
This delegates to the geofilters resolution chain ($_REQUEST['radius'] → per-role setting → default 25, capped at 3000). See the geofilters plugin’s own Hook: mam_geofilter_radius for the chain’s details.
Gotchas
- Comparison is strict less-than. The check is
distance < $radius, not<=. An offer exactly at the boundary will not appear. Returning5.0is functionally identical to returning5. $req_lat/$req_loncome from$_REQUESTviafloatval(). A request with no GPS gets(0, 0). The loop guards this withMAM_Input_Validator::is_null_island( $req_lat, $req_lon ): when the request coordinates are null-island(0, 0), the distance check is short-circuited and every published offer is returned regardless of what this filter returns (a deliberate “show everything when we don’t know where you are” fallback). The radius only takes effect when the device sends real coordinates.- The 5-mile default is per request, not cached. Adding an expensive callback (DB lookup, remote call) here adds latency to every nearby-offers request. If you’re computing the radius from per-user data, cache it.
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)
Re-verify whenever the default radius (5) changes, the comparison operator in get_data_for_app() changes, or the lat/lon source for the request changes from $_REQUEST['lat'] / $_REQUEST['lon'].
Related articles
- Plugin: mam-special-offers
- Hook: mam_specials_get_post_lat — companion hook for overriding parent coordinates
- 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 |
