Signature
apply_filters( 'mam_geodirectory_final_listings', array $dir_details );
| Parameter | Type | Description |
|---|---|---|
$dir_details |
array | Full array of listing rows after every per-listing finaliser has run and the array has been sorted. |
Returns: array — the (possibly modified) listings to send to the app. You must return an array.
Purpose
The last filter the directory pipeline runs before returning. By the time it fires, every listing has been:
- Pulled from the detail table (or supplied via Hook: mam_geodirectory_explcit_listings).
- Filtered by category, status, and authorship rules.
- Run through cache lookup.
- Enriched with category, marker, image, social, claim, and chat data.
- Sorted by title or distance (or
sort_datefor events).
This is the right place to make a global decision: cap the count, attach a header object, swap two listings’ positions, sprinkle ads, etc.
When it runs
return apply_filters( 'mam_geodirectory_final_listings', $dir_details );
End of mam_geodirectory_content::get_data_for_app(). Fires once per request, regardless of which content type triggered it. (Events-only mode runs local_app_sksort first, then this filter.)
Examples
Cap to top 100
add_filter( 'mam_geodirectory_final_listings', static fn( $listings ) => array_slice( $listings, 0, 100 ) );
Promote a specific listing to the top
add_filter( 'mam_geodirectory_final_listings', 'my_app_pin_top_listing' );
function my_app_pin_top_listing( $listings ) {
$top_id = (int) get_option( 'my_app_pinned_listing_id' );
if ( ! $top_id ) {
return $listings;
}
$pinned = null;
foreach ( $listings as $i => $listing ) {
if ( (int) $listing['id'] === $top_id ) {
$pinned = $listing;
unset( $listings[ $i ] );
break;
}
}
if ( $pinned ) {
array_unshift( $listings, $pinned );
}
return array_values( $listings );
}
Drop listings missing a thumbnail
add_filter( 'mam_geodirectory_final_listings', static fn( $listings ) => array_values( array_filter(
$listings,
static fn( $l ) => ! empty( $l['imageurl'] )
) ) );
Gotchas
- Already includes derived fields.
id,lat,lon,title,subcategories,marker_pin,imageurl, etc. — all the keys documented in Mobile listing data shape — are present. Don’t try to add rawpost_id/latitudekeys; the plugin has already removed them. - Filters after this run on the app side. The mobile client may further filter or sort. Any change here is the last server-side pass.
- Order matters for performance. A callback that re-queries the database per listing kills request time. Cache aggressively.
- The plugin runs
mam_tab_managerper listing earlier in the pipeline. If you mutatetab_typeortab_locationhere, those changes don’t take effect — those keys are unset before this filter fires. - Always return an array. Returning a non-array breaks the directory response.
Verification
This article was last verified against:
- Plugin:
mam-geodirectoryv2.1.5 - Source:
content-classes/local-app-geodirectory-v2-class.php(line 637)
Re-verify whenever the per-listing finaliser pipeline is restructured or the sort step moves to a different position.
Related articles
- Plugin: mam-geodirectory
- Mobile listing data shape
- Hook: mam_geodirectory_explcit_listings
- Hook: mam_geodirectory_skip_record
Metadata
| Field | Value |
|---|---|
| Article type | Hook Reference |
| Plugin slug | mam-geodirectory |
| Applies to plugin version | 2.1.5+ |
| Category | Extending MAM Suite |
| Hook type | filter |
| Audience | PHP developer |
| Last verified | 2026-05-01 |
