Goal
Set up the Claim Listing flow so an app user can take ownership of a GeoDirectory listing: optionally request approval first, then complete payment (Stripe or in-app purchase), then have the listing’s post_author re-pointed at them with the claim’s chosen package applied.
This article documents three things:
- The Claim Listing tab bar button state machine (built in
mam_gd_claim_listing_manager::tab_bar_button). - The request → approve → paid AJAX flow (
mam_claim_listing_request/mam_claim_listing_paid). - The legacy claim-cancel form at
includes/forms/claim-listing-form.php, which lets a user cancel the subscription on every listing they author.
Prerequisites
- The third-party GeoDir Claim Manager plugin active. The button checks
class_exists('GeoDir_Claim_Post'); without it the button never appears. - GeoDirectory pricing packages defined for the listing’s post type.
- Settings configured on Mobile App Manager → Geodirectory → Settings:
mam_gd_claim_requires_approval—yesto require admin approval first;noto allow direct purchase.mam_gd_claim_checkout_mode—iaporstripe(string sent to the app to choose the checkout flow).mam_gd_claim_cta— headline text on the claim purchase screen.mam_gd_claim_features— newline-separated bullet list shown to the buyer.
The button states
mam_gd_claim_listing_manager::tab_bar_button($tabbar_button, $tab_key, $data_array):
The button is hidden entirely when:
- The listing’s post type does not support claiming (
GeoDir_Claim_Post::post_claim_allowed($post_id)returns false). - The listing is already claimed.
- The viewer is the listing’s author.
- No user is signed in.
When visible, the button takes one of three forms:
| State | Title | Action | When |
|---|---|---|---|
| Claim pending | “Claim Pending” | empty | GeoDir_Claim_Post::is_claim_pending($post_id) is true. |
| Request to claim | “Request to Claim” | claim_request |
mam_gd_claim_requires_approval === 'yes' AND user has no _mam_claim_approved_{post_id} user meta. |
| Ready for purchase | “Claim Listing” | open_claim_purchase |
Otherwise. Source carries the package list, checkout mode, CTA, and features. |
The “Ready for purchase” payload looks like:
$tabbar_button['source'] = [
'mode' => 'stripe', // or 'iap'
'packages' => [/* package data */],
'post_id' => '12345',
'cta' => 'Claim this listing to manage it',
'features' => ['Manage your listing', 'Respond to reviews', ...],
];
Each package entry: {package_id, product_id, price, term, name, description, order} — sorted by display_order. term is a localised label like ' for one year' or ' per month', derived from the package’s recurring flag and time unit.
The AJAX endpoints
The plugin registers two actions on mam-main‘s mam_main_ajax pipeline:
mam_claim_listing_request→handle_claim_request()mam_claim_listing_paid→handle_claim_payment_complete()
Both are dispatched via mam_main_ajax with subaction=....
mam_claim_listing_request
The “Request to Claim” button calls this when approval is required. It:
- Reads
post_idand the user’scommentsfrom the request. - Returns an error if the user already has a pending claim.
- Builds a claim record via
GeoDir_Claim_Post::save()withstatus: 0(pending) and the user’s IP and full name. - Returns success with a refreshed
jsonData(the user’s phone-data payload).
Admins approve the request out-of-band — typically by setting the _mam_claim_approved_{post_id} user meta on the requestor’s account, which the button’s state machine then picks up. (The admin-side UI for this is not included in mam-geodirectory; it is expected to be added per-deployment, e.g., as an admin tool that watches GeoDir_Claim_Post rows.)
mam_claim_listing_paid
The “Claim Listing” button calls this after the app has completed payment. It:
- Reads
post_idandpackage_id. - Finds the existing pending claim, or creates one inline if no prior request was made (direct-purchase path).
- Calls
GeoDir_Claim_Post::approve_claim($claim->id)— this is the GeoDirectory primitive that flipsclaimed = 1and re-pointspost_author. - Updates the listing’s package via
geodir_pricing_post_update_packagewhen a package is supplied. - Returns success with refreshed
jsonData.
The legacy claim-cancel form
mam_gd_manage_claim_listing::claim_listing() (in includes/forms/claim-listing-form.php) is unrelated to the new claim flow. It is a Gravity Forms result handler registered on mam_for_gravity_forms_form_result_form_{id} for the form ID stored in the option mam_geodirectory_claim_listing.
When the form is submitted with a checkbox set to ON, the handler walks every gd_place post owned by the current user and:
- Sets the listing’s
package_idpost meta to0. - Sets the listing’s
expire_dateto yesterday (date('Y-m-d', strtotime('-1 day'))).
This effectively cancels every paid subscription the user has on gd_place listings. The flow returns Subscription has been cancelled.
Heads up: this code path is sensitive to the
mam_geodirectory_claim_listingoption being non-empty. If the option is empty, the filter is registered asmam_for_gravity_forms_form_result_form_(no ID), which is a no-op but undesirable. Make sure the option is set or remove the filter — the PLUGIN_AUDIT.md flagged this as a behavior bug; the code is unchanged at v2.1.5.
Steps to enable the new claim flow
1. Install the GeoDir Claim Manager plugin
The button silently disappears if GeoDir_Claim_Post is not loaded.
2. Configure claim toggles
Under Settings → Claim Listings:
- Set
mam_gd_claim_requires_approvaltoyesornobased on your policy. - Set
mam_gd_claim_checkout_modetoiap(use App Store / Play Store IAP) orstripe(use Stripe IAP-equivalent on the device). The plugin does not validate this string; whatever you put there is sent verbatim to the app. - Set the CTA and features list.
3. Configure pricing packages
Each gd_place (or other claimable post type) should have at least one pricing package. The package’s woocommerce_product_id meta is sent as product_id — required for IAP flows.
4. Verify
- Open the app as a non-author signed-in user. Pick a claimable, unclaimed listing.
- With
mam_gd_claim_requires_approval=yes: tap Request to Claim. Verify a pending row appears inGeoDir_Claim_Post. - After approval (set the user-meta flag manually), reopen the listing. The button should now read Claim Listing and open the purchase screen.
- Complete a test purchase. Confirm the listing’s
post_authoris the new user andclaim_status: claimedappears in subsequent app responses.
Variations
- Direct purchase (no approval). Set
mam_gd_claim_requires_approval=no. The button skips straight to purchase. - Custom features list. Edit the multi-line
mam_gd_claim_featuresoption. The plugin trims and filters empty lines. - Default features. When the option is empty, the plugin uses a built-in trio: “Manage your listing,” “Respond to reviews,” “Post special offers.”
Verification
This article was last verified against:
- Plugin:
mam-geodirectoryv2.1.5 - Source:
includes/mam_gd_claim_listing_manager.php - Source:
includes/forms/claim-listing-form.php(legacy cancel form) - Required: GeoDir Claim Manager plugin (
GeoDir_Claim_Post)
Re-verify whenever the claim button state machine changes, the package field shape sent to the app changes, the AJAX subaction names change, or the legacy cancel-subscription form is removed.
Related articles
- Plugin: mam-geodirectory
- Recipe: Configure the GeoDirectory settings page
- Recipe: Bulk-invite venue owners
- Listing tab bar buttons
- Mobile listing data shape —
claim_statusandcan_claimkeys - GeoDirectory notification types — claim invitation slug
Metadata
| Field | Value |
|---|---|
| Article type | Recipe (Admin) |
| Plugin slug | mam-geodirectory |
| Applies to plugin version | 2.1.5+ |
| Category | Building Your App |
| Audience | WordPress admin |
| Estimated time | 15 minutes |
| Last verified | 2026-05-01 |
