{
  "$schema": "https://wpmediaverse.com/schemas/wp-plugin-manifest-v2.json",
  "plugin": {
    "slug": "wb-listora",
    "name": "WB Listora",
    "version": "1.2.0",
    "namespace": "WBListora",
    "main_file": "wb-listora.php",
    "text_domain": "wb-listora",
    "extends": null,
    "extension_hook_consumed": null,
    "extension_hook_fired": "wb_listora_loaded",
    "rest_namespace": "listora/v1",
    "table_prefix": "listora_",
    "meta_prefix": "_listora_",
    "min_php": "7.4",
    "min_wp": "6.9"
  },
  "rest": {
    "namespace": "listora/v1",
    "endpoints": [
      {
        "route": "/listora/v1/listings",
        "methods": [
          "GET"
        ],
        "handler": "Listings_Controller::get_items",
        "permission": "__return_true",
        "purpose": "List published listings (cursor pagination)"
      },
      {
        "route": "/listora/v1/listings/{id}/detail",
        "methods": [
          "GET"
        ],
        "handler": "Listings_Controller::get_listing",
        "permission": "__return_true",
        "purpose": "Single listing detail (card or full)"
      },
      {
        "route": "/listora/v1/listings/{id}",
        "methods": [
          "DELETE"
        ],
        "handler": "Listings_Controller::delete_listing",
        "permission": "delete_listing_permissions",
        "purpose": "Owner soft-delete"
      },
      {
        "route": "/listora/v1/listings/{id}/feature",
        "methods": [
          "POST"
        ],
        "handler": "Listings_Controller::feature_listing",
        "permission": "feature_listing_permissions",
        "purpose": "Upgrade listing to Featured"
      },
      {
        "route": "/listora/v1/listings/{id}/deactivate",
        "methods": [
          "POST"
        ],
        "handler": "Listings_Controller::deactivate_listing",
        "permission": "deactivate_listing_permissions",
        "purpose": "Owner hides their listing from the directory (sets listora_deactivated status)"
      },
      {
        "route": "/listora/v1/listings/{id}/reactivate",
        "methods": [
          "POST"
        ],
        "handler": "Listings_Controller::reactivate_listing",
        "permission": "reactivate_listing_permissions",
        "purpose": "Owner restores a deactivated listing back to its prior published/pending status"
      },
      {
        "route": "/listora/v1/listings/{id}/related",
        "methods": [
          "GET"
        ],
        "handler": "Listings_Controller::get_related",
        "permission": "__return_true",
        "purpose": "Related listings"
      },
      {
        "route": "/listora/v1/listings/{id}/renewal-quote",
        "methods": [
          "GET"
        ],
        "handler": "Listings_Controller::get_renewal_quote",
        "permission": "renew_listing_permissions",
        "purpose": "Renewal pricing/status"
      },
      {
        "route": "/listora/v1/listings/{id}/renew",
        "methods": [
          "POST"
        ],
        "handler": "Listings_Controller::renew_listing",
        "permission": "renew_listing_permissions",
        "purpose": "Renew expired listing"
      },
      {
        "route": "/listora/v1/listings/bulk",
        "methods": [
          "POST"
        ],
        "handler": "Listings_Controller::get_bulk",
        "permission": "__return_true",
        "purpose": "Fetch up to 50 listings by ID (offline cache)"
      },
      {
        "route": "/listora/v1/listings/{listing_id}/reviews",
        "methods": [
          "GET",
          "POST"
        ],
        "handler": "Reviews_Controller::get_listing_reviews / create_review",
        "permission": "__return_true / create_review_permissions",
        "purpose": "List reviews / submit new review"
      },
      {
        "route": "/listora/v1/reviews/{id}",
        "methods": [
          "PUT",
          "DELETE"
        ],
        "handler": "Reviews_Controller::update_review / delete_review",
        "permission": "update_review_permissions / delete_review_permissions",
        "purpose": "Update/delete review"
      },
      {
        "route": "/listora/v1/reviews/{id}/helpful",
        "methods": [
          "POST"
        ],
        "handler": "Reviews_Controller::vote_helpful",
        "permission": "logged_in_permissions",
        "purpose": "Helpful vote"
      },
      {
        "route": "/listora/v1/reviews/{id}/reply",
        "methods": [
          "POST"
        ],
        "handler": "Reviews_Controller::owner_reply",
        "permission": "owner_reply_permissions",
        "purpose": "Listing owner reply"
      },
      {
        "route": "/listora/v1/reviews/{id}/report",
        "methods": [
          "POST"
        ],
        "handler": "Reviews_Controller::report_review",
        "permission": "logged_in_permissions",
        "purpose": "Report inappropriate review"
      },
      {
        "route": "/listora/v1/dashboard/stats",
        "methods": [
          "GET"
        ],
        "handler": "Dashboard_Controller::get_stats",
        "permission": "logged_in_permissions",
        "purpose": "User dashboard stats (60s transient)"
      },
      {
        "route": "/listora/v1/dashboard/listings",
        "methods": [
          "GET"
        ],
        "handler": "Dashboard_Controller::get_listings",
        "permission": "logged_in_permissions",
        "purpose": "User's listings (cursor pagination)"
      },
      {
        "route": "/listora/v1/dashboard/reviews",
        "methods": [
          "GET"
        ],
        "handler": "Dashboard_Controller::get_reviews",
        "permission": "logged_in_permissions",
        "purpose": "User's reviews received/written"
      },
      {
        "route": "/listora/v1/dashboard/claims",
        "methods": [
          "GET"
        ],
        "handler": "Dashboard_Controller::get_my_claims",
        "permission": "logged_in_permissions",
        "purpose": "User's claim requests"
      },
      {
        "route": "/listora/v1/dashboard/profile",
        "methods": [
          "GET",
          "PUT"
        ],
        "handler": "Dashboard_Controller::get_profile / update_profile",
        "permission": "logged_in_permissions",
        "purpose": "Dashboard profile (name, bio)"
      },
      {
        "route": "/listora/v1/dashboard/notifications",
        "methods": [
          "GET"
        ],
        "handler": "Dashboard_Controller::get_notifications",
        "permission": "logged_in_permissions",
        "purpose": "In-app notifications"
      },
      {
        "route": "/listora/v1/dashboard/notifications/read",
        "methods": [
          "PUT"
        ],
        "handler": "Dashboard_Controller::mark_notifications_read",
        "permission": "logged_in_permissions",
        "purpose": "Mark notifications read"
      },
      {
        "route": "/listora/v1/favorites",
        "methods": [
          "GET",
          "POST"
        ],
        "handler": "Favorites_Controller::get_favorites / add_favorite",
        "permission": "logged_in_permissions",
        "purpose": "List/add favorites"
      },
      {
        "route": "/listora/v1/favorites/{listing_id}",
        "methods": [
          "DELETE"
        ],
        "handler": "Favorites_Controller::remove_favorite",
        "permission": "logged_in_permissions",
        "purpose": "Remove favorite"
      },
      {
        "route": "/listora/v1/search",
        "methods": [
          "GET"
        ],
        "handler": "Search_Controller::search",
        "permission": "__return_true",
        "purpose": "Filtered/geo/fulltext/facet search"
      },
      {
        "route": "/listora/v1/search/suggest",
        "methods": [
          "GET"
        ],
        "handler": "Search_Controller::suggest",
        "permission": "__return_true",
        "purpose": "Autocomplete suggestions"
      },
      {
        "route": "/listora/v1/claims",
        "methods": [
          "GET",
          "POST"
        ],
        "handler": "Claims_Controller::get_claims / submit_claim",
        "permission": "admin_permissions / logged_in_permissions",
        "purpose": "List all claims (admin) / submit claim"
      },
      {
        "route": "/listora/v1/claims/{id}",
        "methods": [
          "PUT"
        ],
        "handler": "Claims_Controller::update_claim",
        "permission": "admin_permissions",
        "purpose": "Approve/reject claim"
      },
      {
        "route": "/listora/v1/submit",
        "methods": [
          "POST"
        ],
        "handler": "Submission_Controller::submit_listing",
        "permission": "submit_listing_permissions",
        "purpose": "Frontend listing submission"
      },
      {
        "route": "/listora/v1/submit/check-duplicate",
        "methods": [
          "POST"
        ],
        "handler": "Submission_Controller::check_duplicate_endpoint",
        "permission": "logged_in_permissions",
        "purpose": "Pre-submit duplicate check"
      },
      {
        "route": "/listora/v1/submit/{id}",
        "methods": [
          "PUT"
        ],
        "handler": "Submission_Controller::edit_listing",
        "permission": "edit_listing_permissions",
        "purpose": "Owner edit listing"
      },
      {
        "route": "/listora/v1/submission/resend-verification",
        "methods": [
          "POST"
        ],
        "handler": "Submission_Controller::resend_verification_endpoint",
        "permission": "__return_true",
        "purpose": "Resend email verification"
      },
      {
        "route": "/listora/v1/submission/verify",
        "methods": [
          "GET"
        ],
        "handler": "Submission_Controller::verify_endpoint",
        "permission": "__return_true",
        "purpose": "REST mirror of email verify URL"
      },
      {
        "route": "/listora/v1/listing-types",
        "methods": [
          "GET",
          "POST"
        ],
        "handler": "Listing_Types_Controller::get_items / create_item",
        "permission": "__return_true / create_item_permissions_check",
        "purpose": "List/create listing types"
      },
      {
        "route": "/listora/v1/listing-types/{slug}",
        "methods": [
          "GET",
          "PUT",
          "DELETE"
        ],
        "handler": "Listing_Types_Controller::get_item / update_item / delete_item",
        "permission": "scoped",
        "purpose": "CRUD single listing type"
      },
      {
        "route": "/listora/v1/listing-types/{slug}/fields",
        "methods": [
          "GET"
        ],
        "handler": "Listing_Types_Controller::get_fields",
        "permission": "__return_true",
        "purpose": "Type fields schema"
      },
      {
        "route": "/listora/v1/listing-types/{slug}/categories",
        "methods": [
          "GET"
        ],
        "handler": "Listing_Types_Controller::get_categories",
        "permission": "__return_true",
        "purpose": "Categories scoped to a listing type"
      },
      {
        "route": "/listora/v1/listings/{listing_id}/services",
        "methods": [
          "GET",
          "POST"
        ],
        "handler": "Services_Controller::get_listing_services / create_service",
        "permission": "__return_true / create_service_permissions",
        "purpose": "Listing services list/create"
      },
      {
        "route": "/listora/v1/services/{id}",
        "methods": [
          "GET",
          "PUT",
          "DELETE"
        ],
        "handler": "Services_Controller::get_service / update_service / delete_service",
        "permission": "scoped",
        "purpose": "CRUD single service"
      },
      {
        "route": "/listora/v1/listings/{listing_id}/services/reorder",
        "methods": [
          "POST"
        ],
        "handler": "Services_Controller::reorder_services",
        "permission": "create_service_permissions",
        "purpose": "Reorder services"
      },
      {
        "route": "/listora/v1/settings",
        "methods": [
          "GET",
          "PUT",
          "DELETE"
        ],
        "handler": "Settings_Controller::get_all_settings / update_settings / reset_settings",
        "permission": "manage_listora_settings",
        "purpose": "Plugin settings CRUD"
      },
      {
        "route": "/listora/v1/settings/maps",
        "methods": [
          "GET"
        ],
        "handler": "Settings_Controller::get_map_settings",
        "permission": "__return_true",
        "purpose": "Public map config"
      },
      {
        "route": "/listora/v1/settings/app-config",
        "methods": [
          "GET"
        ],
        "handler": "Settings_Controller::get_app_config",
        "permission": "__return_true",
        "purpose": "Public bootstrap config (app/frontend)"
      },
      {
        "route": "/listora/v1/settings/export",
        "methods": [
          "GET"
        ],
        "handler": "Settings_Controller::export_settings",
        "permission": "manage_listora_settings",
        "purpose": "Export settings JSON"
      },
      {
        "route": "/listora/v1/settings/import",
        "methods": [
          "POST"
        ],
        "handler": "Settings_Controller::import_settings",
        "permission": "manage_listora_settings",
        "purpose": "Import settings JSON"
      },
      {
        "route": "/listora/v1/settings/notifications/test",
        "methods": [
          "POST"
        ],
        "handler": "Settings_Controller::send_test_notification",
        "permission": "manage_listora_settings",
        "purpose": "Send test notification email"
      },
      {
        "route": "/listora/v1/settings/notifications/log",
        "methods": [
          "GET",
          "DELETE"
        ],
        "handler": "Settings_Controller::get_notification_log / clear_notification_log",
        "permission": "manage_listora_settings",
        "purpose": "View/clear notification log"
      },
      {
        "route": "/listora/v1/settings/notifications/log/export",
        "methods": [
          "GET"
        ],
        "handler": "Settings_Controller::export_notification_log",
        "permission": "manage_listora_settings",
        "purpose": "Download notification log as CSV/JSON for archiving"
      },
      {
        "route": "/listora/v1/settings/notifications/log/retention",
        "methods": [
          "POST"
        ],
        "handler": "Settings_Controller::set_notification_retention",
        "permission": "manage_listora_settings",
        "purpose": "Set notification log retention policy (days)"
      },
      {
        "route": "/listora/v1/export/csv",
        "methods": [
          "GET"
        ],
        "handler": "Import_Export_Controller::export_csv",
        "permission": "manage_options",
        "purpose": "Export listings CSV"
      },
      {
        "route": "/listora/v1/import/csv",
        "methods": [
          "POST"
        ],
        "handler": "Import_Export_Controller::import_csv",
        "permission": "manage_options",
        "purpose": "Import CSV"
      },
      {
        "route": "/listora/v1/import/json",
        "methods": [
          "POST"
        ],
        "handler": "Import_Export_Controller::import_json",
        "permission": "manage_options",
        "purpose": "Import JSON"
      },
      {
        "route": "/listora/v1/import/geojson",
        "methods": [
          "POST"
        ],
        "handler": "Import_Export_Controller::import_geojson",
        "permission": "manage_options",
        "purpose": "Import GeoJSON with geo"
      },
      {
        "route": "/listora/v1/listings/bulk-moderate",
        "methods": [
          "POST"
        ],
        "handler": "WBListora\\REST\\Listings_Controller::bulk_moderate",
        "permission": "edit_others_listora_listings (top-level cap + edit_post per-ID re-check inside loop)",
        "purpose": "Bulk moderation — approve/reject/feature/unfeature/trash up to 100 listings per call. Returns per-ID succeeded[]/failed[] arrays. Fires wb_listora_after_bulk_moderate."
      },
      {
        "route": "/listora/v1/listings/(?P<id>[\\d]+)/contact-form",
        "methods": [
          "POST"
        ],
        "handler": "WBListora\\Contact_Form::handle_rest_submission",
        "permission": "__return_true (anonymous allowed; nonce + honeypot + Anti_Spam pipeline gate inside handler)",
        "purpose": "Free's listing contact form. Per-IP-per-listing 3/hour cap + per-listing 20/day cap (filterable). Pro's lead_form takes /listings/{id}/contact (different route); the two never render together — Contact_Form::should_render() bails when wb_listora_pro_feature_enabled('lead_form') returns true."
      },
      {
        "route": "/listora/v1/import/queue/csv",
        "methods": [
          "POST"
        ],
        "handler": "Background_Import::rest_queue_csv",
        "permission": "Background_Import::progress_permissions (manage_options)",
        "purpose": "Stage an uploaded CSV and queue a resumable, idempotent background import on the canonical Background_Import engine. Returns the run_id the admin UI polls against /import/progress/{run_id}. Mirrors Import_Export_Controller::import_csv validation (file presence, MIME allowlist, mapping decode) so both import paths reject the same malformed input. Self-registered inside Background_Import on wb_listora_rest_api_init (1.2.0 wave-4)."
      },
      {
        "route": "/listora/v1/import/progress/{run_id}",
        "methods": [
          "GET"
        ],
        "handler": "Background_Import::rest_progress",
        "permission": "Background_Import::progress_permissions",
        "purpose": "Poll background demo/CSV import progress (1.2.0 wave-4; admin-gated)"
      },
      {
        "route": "/listora/v1/unsubscribe",
        "methods": [
          "GET"
        ],
        "handler": "Unsubscribe_Controller::handle_unsubscribe",
        "permission": "__return_true (public by design — signed HMAC token uid|event vs wp_salt('wb_listora_unsubscribe') is the credential; RFC 8058 one-click opt-out, hash_equals compare)",
        "purpose": "One-click email unsubscribe for marketing/nudge notification events; flips _listora_notify_{event} user meta and renders an HTML confirmation page (1.2.0). NOTE: GET only — earlier audit notes claiming GET/POST were wrong."
      }
    ]
  },
  "ajax": [
    {
      "action": "listora_dismiss_onboarding",
      "handler": "Admin::ajax_dismiss_onboarding",
      "where": "includes/admin/class-admin.php",
      "nonce": "listora_admin_nonce",
      "capability": "manage_listora_settings",
      "purpose": "Dismiss onboarding banner"
    },
    {
      "action": "listora_run_migration",
      "handler": "Admin::ajax_run_migration",
      "where": "includes/admin/class-admin.php",
      "nonce": "listora_admin_nonce",
      "capability": "manage_listora_settings",
      "purpose": "Run DB migration from admin"
    },
    {
      "action": "wb_listora_validate_license",
      "handler": "Pro_Promotion::ajax_validate_license",
      "where": "includes/admin/class-pro-promotion.php",
      "nonce": "wb_listora_promo_nonce",
      "capability": "manage_listora_settings",
      "purpose": "Validate Pro license key from promo CTA"
    },
    {
      "action": "wb_listora_dismiss_promo",
      "handler": "Pro_Promotion::ajax_dismiss_promo",
      "where": "includes/admin/class-pro-promotion.php",
      "nonce": "wb_listora_promo_nonce",
      "capability": "manage_listora_settings",
      "purpose": "Dismiss Pro promo (3-day cookie)"
    },
    {
      "action": "listora_run_demo_import",
      "handler": "Settings_Page::ajax_run_demo_import",
      "where": "includes/admin/class-admin.php:80 (registration); includes/admin/class-settings-page.php:2794 (handler)",
      "nonce": "listora_demo_import",
      "capability": "manage_options",
      "purpose": "Queue a background demo-pack import run via Background_Import::queue_demo; fires wb_listora_demo_import_run (1.2.0)"
    }
  ],
  "admin_pages": [
    {
      "title": "Listora",
      "slug": "listora",
      "parent": null,
      "capability": "edit_listora_listings",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Dashboard",
      "slug": "listora",
      "parent": "listora",
      "capability": "edit_listora_listings",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Listing Types",
      "slug": "listora-listing-types",
      "parent": "listora",
      "capability": "manage_listora_types",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Categories",
      "slug": "edit-tags.php?taxonomy=listora_listing_cat&post_type=listora_listing",
      "parent": "listora",
      "capability": "manage_listora_types",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Locations",
      "slug": "edit-tags.php?taxonomy=listora_listing_location&post_type=listora_listing",
      "parent": "listora",
      "capability": "manage_listora_types",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Features",
      "slug": "edit-tags.php?taxonomy=listora_listing_feature&post_type=listora_listing",
      "parent": "listora",
      "capability": "manage_listora_types",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Reviews",
      "slug": "listora-reviews",
      "parent": "listora",
      "capability": "manage_listora_types",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Claims",
      "slug": "listora-claims",
      "parent": "listora",
      "capability": "manage_listora_types",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Settings",
      "slug": "listora-settings",
      "parent": "listora",
      "capability": "manage_listora_settings",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Email Log",
      "slug": "listora-email-log",
      "parent": "listora",
      "capability": "manage_listora_settings",
      "source": "includes/admin/class-admin.php"
    },
    {
      "title": "Health Check",
      "slug": "listora-health",
      "parent": "",
      "capability": "manage_listora_settings",
      "source": "includes/admin/class-admin.php",
      "note": "Hidden stub — parent '' hides from sidebar. Redirects to Settings > Advanced tab. Registered so wp-admin page-not-registered check doesn't fire on direct URL access."
    },
    {
      "title": "Setup Wizard",
      "slug": "listora-setup",
      "parent": "listora",
      "capability": "manage_listora_settings",
      "source": "includes/admin/class-admin.php",
      "note": "Dynamic parent: 'listora' when setup is incomplete (visible in sidebar), '' when setup_complete=true (hidden). Parent must be '' not null — PHP 8 strpos(null) deprecation fix (2026-05-12)."
    },
    {
      "title": "WB Listora Pro",
      "slug": "listora-pro-promotion",
      "parent": "listora",
      "capability": "manage_listora_settings",
      "source": "includes/admin/class-pro-promotion.php"
    }
  ],
  "settings": [
    {
      "key": "wb_listora_settings",
      "group": "wb_listora_settings_group",
      "type": "array",
      "default": {},
      "controls": "Master settings array — General, Submissions, Maps, Reviews, Credits, Features, Import/Export tabs; 1.2.0: + submission_form_style sub-key (wizard|single_form) — drives listing-submission block layout via wb_listora_submission_layout_mode"
    },
    {
      "key": "wb_listora_overflow_cost",
      "group": "wb_listora_settings_group",
      "type": "integer",
      "default": 10,
      "controls": "Credit cost for overflow listings beyond plan limit"
    },
    {
      "key": "wb_listora_low_credit_threshold",
      "group": "wb_listora_settings_group",
      "type": "integer",
      "default": 5,
      "controls": "Low credit balance alert threshold"
    },
    {
      "key": "wb_listora_setup_complete",
      "group": null,
      "type": "boolean",
      "default": false,
      "controls": "Setup wizard completion flag"
    },
    {
      "key": "wb_listora_features",
      "group": null,
      "type": "array",
      "default": {},
      "controls": "Feature flags: reviews_enabled, claims_enabled, events_enabled, services_enabled"
    }
  ],
  "shortcodes": [],
  "blocks": [
    {
      "name": "listora/listing-grid",
      "render": "blocks/listing-grid/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/listing-card",
      "render": "blocks/listing-card/render.php",
      "interactivity": true,
      "layout_owning": false
    },
    {
      "name": "listora/listing-search",
      "render": "blocks/listing-search/render.php",
      "interactivity": true,
      "layout_owning": false
    },
    {
      "name": "listora/listing-map",
      "render": "blocks/listing-map/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/listing-detail",
      "render": "blocks/listing-detail/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/listing-reviews",
      "render": "blocks/listing-reviews/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/listing-submission",
      "render": "blocks/listing-submission/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/listing-categories",
      "render": "blocks/listing-categories/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/listing-featured",
      "render": "blocks/listing-featured/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/listing-calendar",
      "render": "blocks/listing-calendar/render.php",
      "interactivity": true,
      "layout_owning": true
    },
    {
      "name": "listora/user-dashboard",
      "render": "blocks/user-dashboard/render.php",
      "interactivity": true,
      "layout_owning": true
    }
  ],
  "post_types": [
    {
      "name": "listora_listing",
      "public": true,
      "has_archive": true,
      "supports": [
        "title",
        "editor",
        "thumbnail",
        "excerpt",
        "author",
        "comments",
        "revisions"
      ],
      "capability_type": "listora_listing",
      "custom_statuses": [
        "listora_rejected",
        "listora_expired",
        "listora_deactivated",
        "listora_payment"
      ],
      "source": "includes/core/class-post-types.php"
    }
  ],
  "taxonomies": [
    {
      "name": "listora_listing_type",
      "post_type": "listora_listing",
      "hierarchical": false,
      "show_ui": false,
      "rewrite": "listing-type",
      "capabilities": {
        "manage_terms": "manage_listora_types",
        "edit_terms": "manage_listora_types",
        "delete_terms": "manage_listora_types",
        "assign_terms": "edit_listora_listings"
      }
    },
    {
      "name": "listora_listing_cat",
      "post_type": "listora_listing",
      "hierarchical": true,
      "show_ui": true,
      "rewrite": "listing-category",
      "capabilities": {
        "manage_terms": "manage_listora_types",
        "edit_terms": "manage_listora_types",
        "delete_terms": "manage_listora_types",
        "assign_terms": "edit_listora_listings"
      }
    },
    {
      "name": "listora_listing_tag",
      "post_type": "listora_listing",
      "hierarchical": false,
      "show_ui": true,
      "rewrite": "listing-tag",
      "capabilities": {
        "manage_terms": "manage_listora_types",
        "edit_terms": "edit_listora_listings",
        "delete_terms": "manage_listora_types",
        "assign_terms": "edit_listora_listings"
      }
    },
    {
      "name": "listora_listing_location",
      "post_type": "listora_listing",
      "hierarchical": true,
      "show_ui": true,
      "rewrite": "listing-location",
      "capabilities": {
        "manage_terms": "manage_listora_types",
        "edit_terms": "manage_listora_types",
        "delete_terms": "manage_listora_types",
        "assign_terms": "edit_listora_listings"
      }
    },
    {
      "name": "listora_listing_feature",
      "post_type": "listora_listing",
      "hierarchical": false,
      "show_ui": true,
      "rewrite": "listing-feature",
      "capabilities": {
        "manage_terms": "manage_listora_types",
        "edit_terms": "manage_listora_types",
        "delete_terms": "manage_listora_types",
        "assign_terms": "edit_listora_listings"
      }
    },
    {
      "name": "listora_service_cat",
      "post_type": "listora_listing",
      "hierarchical": false,
      "show_ui": true,
      "rewrite": "service-category",
      "capabilities": {
        "manage_terms": "manage_listora_types",
        "edit_terms": "manage_listora_types",
        "delete_terms": "manage_listora_types",
        "assign_terms": "edit_listora_listings"
      }
    }
  ],
  "tables": [
    {
      "name": "listora_geo",
      "purpose": "Geo index (lat/lng/geohash/timezone) for location queries"
    },
    {
      "name": "listora_search_index",
      "purpose": "Denormalized listing index for fulltext + facet + filter"
    },
    {
      "name": "listora_field_index",
      "purpose": "Custom-field filter index (faceted search per listing type)"
    },
    {
      "name": "listora_reviews",
      "purpose": "Reviews with rating, criteria, photos, owner reply, helpful count"
    },
    {
      "name": "listora_review_votes",
      "purpose": "Helpful-vote tracking per (user, review)"
    },
    {
      "name": "listora_favorites",
      "purpose": "User favorites with optional collection name"
    },
    {
      "name": "listora_claims",
      "purpose": "Business ownership claims with proof + admin workflow"
    },
    {
      "name": "listora_hours",
      "purpose": "Denormalized business hours for 'open now' queries"
    },
    {
      "name": "listora_analytics",
      "purpose": "Listing analytics events (used by Pro)"
    },
    {
      "name": "listora_payments",
      "purpose": "Payment transactions (one-time + subscription, refunds)"
    },
    {
      "name": "listora_services",
      "purpose": "Listing services/offerings with price, duration, gallery"
    }
  ],
  "capabilities": [
    {
      "cap": "edit_listora_listing",
      "default_roles": [
        "administrator",
        "editor",
        "author",
        "contributor"
      ],
      "meta": true,
      "requires_context": "post"
    },
    {
      "cap": "edit_listora_listings",
      "default_roles": [
        "administrator",
        "editor",
        "author",
        "contributor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "edit_others_listora_listings",
      "default_roles": [
        "administrator",
        "editor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "edit_published_listora_listings",
      "default_roles": [
        "administrator",
        "editor",
        "author"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "publish_listora_listings",
      "default_roles": [
        "administrator",
        "editor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "delete_listora_listing",
      "default_roles": [
        "administrator",
        "editor",
        "author",
        "contributor"
      ],
      "meta": true,
      "requires_context": "post"
    },
    {
      "cap": "delete_listora_listings",
      "default_roles": [
        "administrator",
        "editor",
        "author",
        "contributor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "delete_others_listora_listings",
      "default_roles": [
        "administrator",
        "editor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "delete_published_listora_listings",
      "default_roles": [
        "administrator",
        "editor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "read_private_listora_listings",
      "default_roles": [
        "administrator",
        "editor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "manage_listora_settings",
      "default_roles": [
        "administrator"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "moderate_listora_reviews",
      "default_roles": [
        "administrator",
        "editor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "manage_listora_claims",
      "default_roles": [
        "administrator",
        "editor"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "manage_listora_types",
      "default_roles": [
        "administrator"
      ],
      "meta": false,
      "requires_context": "none"
    },
    {
      "cap": "submit_listora_listing",
      "default_roles": [
        "administrator",
        "editor",
        "author",
        "contributor",
        "subscriber"
      ],
      "meta": false,
      "requires_context": "none"
    }
  ],
  "services": [
    {
      "key": "listing_types",
      "class": "WBListora\\Core\\Listing_Type_Registry",
      "added": "1.0.0"
    },
    {
      "key": "featured",
      "class": "WBListora\\Services\\Featured_Service",
      "added": "1.0.0"
    },
    {
      "key": "meta",
      "class": "WBListora\\Services\\Meta_Service",
      "added": "1.0.0"
    },
    {
      "key": "services",
      "class": "WBListora\\Services\\Services_Service",
      "added": "1.0.0"
    },
    {
      "key": "search_indexer",
      "class": "WBListora\\Search\\Search_Indexer",
      "added": "1.0.0"
    },
    {
      "key": "search_engine",
      "class": "WBListora\\Search\\Search_Engine",
      "added": "1.0.0"
    },
    {
      "key": "geo_query",
      "class": "WBListora\\Services\\Geo_Query_Service",
      "added": "1.0.0"
    },
    {
      "key": "block_css",
      "class": "WBListora\\Services\\Block_CSS_Service",
      "added": "1.0.0"
    },
    {
      "key": "rate_limiter",
      "class": "\\WBListora\\Rate_Limiter",
      "added": "1.0.0",
      "purpose": "Per-user + per-IP transient gate behind every public POST endpoint (ADR-001)."
    }
  ],
  "hooks_fired": [
    {
      "name": "the_content",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "WP_Post|int $post->post_content"
      ],
      "where": "includes/rest/class-listings-controller.php:543",
      "purpose": "Hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/class-plugin.php:166"
        },
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/class-plugin.php:400"
        }
      ]
    },
    {
      "name": "wb_listora_after_add_favorite",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $listing_id",
        "int $user_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-favorites-controller.php:258",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:86"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:198",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_approve_listing",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "WP_Post|int $post->ID"
      ],
      "where": "wb-listora.php:406",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_bulk_moderate",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "string $action",
        "array $ok",
        "array $failed"
      ],
      "where": "includes/rest/class-listings-controller.php:531",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_calendar",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-calendar/render.php:215",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_card",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card.php:66",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_card_actions",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card-actions.php:29",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_card_content",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card-content.php:130",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_card_image",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card-image.php:75",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_categories_grid",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-categories/render.php:89",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_contact_form_submit",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $listing_id",
        "array $context",
        "WP_REST_Request $request"
      ],
      "where": "includes/class-contact-form.php:253",
      "consumed_by": [],
      "purpose": " [2026-06-10 refresh: stale consumed_by cleared — no current listener in Free or Pro; Free pro-promotion CTAs on this hook were retired]"
    },
    {
      "name": "wb_listora_after_create_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-submission-controller.php:512",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:75"
        },
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/search/class-search-indexer.php:60"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:184",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:144",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_create_review",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $review_id",
        "int $listing_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:533",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:81"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:189",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-moderator.php:88",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_create_service",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $service_id",
        "array|mixed $data"
      ],
      "where": "includes/core/class-services.php:196",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:202",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_dashboard_claims",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-claims.php:123",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_dashboard_credits",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-credits.php:218",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_dashboard_listings",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-listings.php:404",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_dashboard_nav",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/nav.php:113",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_dashboard_profile",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-profile.php:86",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_dashboard_reviews",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-reviews.php:80",
      "purpose": "Post-action hook for extension [2026-06-10 refresh: stale consumed_by cleared — no current listener in Free or Pro; Free pro-promotion CTAs on this hook were retired]",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_deactivate_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-listings-controller.php:970",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_delete_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-listings-controller.php:876",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:77"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:186",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_delete_review",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $review_id",
        "int $review ? (int) $review->listing_id : null",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:682",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:83"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:191",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_delete_service",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $service_id",
        "mixed($existing) $existing"
      ],
      "where": "includes/core/class-services.php:342",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:204",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_detail_gallery",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-detail/gallery.php:67",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_detail_sidebar",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-detail/sidebar.php:83",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_detail_tabs",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-detail/tabs.php:464",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_email_verified",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($new_status) $new_status"
      ],
      "where": "includes/admin/class-listing-columns.php:468",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_feature_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($context) $context"
      ],
      "where": "includes/core/class-featured.php:179",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_featured_listings",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($featured_block_attributes) $featured_block_attributes"
      ],
      "where": "blocks/listing-featured/render.php:96",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_listing_card",
      "type": "action",
      "args_count": 5,
      "args_signature": [
        "mixed $id",
        "mixed $layout",
        "mixed $show_rating",
        "mixed $show_favorite",
        "mixed $show_type"
      ],
      "where": "blocks/listing-card/render.php:197",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_listing_fields",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($detail_type_slug) $detail_type_slug"
      ],
      "where": "templates/blocks/listing-detail/sidebar.php:70",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-lead-form.php:30",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-multi-criteria-reviews.php:42",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-verification.php:36",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_listing_grid",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($grid_block_attributes) $grid_block_attributes"
      ],
      "where": "blocks/listing-grid/render.php:216",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_map",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-map/render.php:155",
      "purpose": "Post-action hook for extension [2026-06-10 refresh: stale consumed_by cleared — no current listener in Free or Pro; Free pro-promotion CTAs on this hook were retired]",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_reactivate_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-listings-controller.php:1106",
      "purpose": "Fires after a listing is reactivated via REST. Lets Pro re-run validations or reseed expiry/featured state.",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_reject_listing",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "WP_Post|int $post->ID"
      ],
      "where": "wb-listora.php:410",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_remove_favorite",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $listing_id",
        "int $user_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-favorites-controller.php:316",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:87"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:199",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_renew_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed"
      ],
      "where": "includes/rest/class-listings-controller.php:1562",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:39",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_reset_settings",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "array $option_keys"
      ],
      "where": "includes/rest/class-settings-controller.php:371",
      "purpose": "Fires after a settings reset. Pro re-seeds extension defaults so users see a clean Pro-aware default state.",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:47",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_reviews",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-reviews/reviews.php:128",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_search_results",
      "type": "action",
      "args_count": 0,
      "args_signature": [],
      "where": "templates/blocks/listing-search/search.php:85",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-advanced-search.php:47",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_service_detail",
      "type": "action",
      "args_count": 5,
      "args_signature": [
        "mixed $svc",
        "mixed $post_id",
        "mixed $show_reviews",
        "mixed $detail_reviews",
        "mixed $avg"
      ],
      "where": "templates/blocks/listing-detail/tabs.php:313",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-services-pro.php:58",
          "callback": "Services_Pro::fire_booking_hook",
          "args_count": 2
        }
      ]
    },
    {
      "name": "wb_listora_after_submit_claim",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $claim_id",
        "int $listing_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-claims-controller.php:219",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:194",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-moderator.php:89",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:173",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_template",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "mixed($template_name) $template_name",
        "mixed($template_path) $template_path",
        "array $args"
      ],
      "where": "includes/class-template-helpers.php:89",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_unfeature_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($reason) $reason"
      ],
      "where": "includes/core/class-featured.php:228",
      "purpose": "Post-action hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_update_claim",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $claim_id",
        "mixed($new_status) $new_status",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-claims-controller.php:549",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:195",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:176",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_update_listing",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-submission-controller.php:676",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:76"
        },
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/search/class-search-indexer.php:61"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:185",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:147",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_update_review",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $review_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:615",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-cache.php:82"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:190",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:170",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_after_update_service",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $service_id",
        "array|mixed $data"
      ],
      "where": "includes/core/class-services.php:289",
      "purpose": "Post-action hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:203",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_analytics_retention_days",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "int"
      ],
      "where": "includes/workflow/class-expiration-cron.php:232",
      "purpose": "Plugin extension hook",
      "consumed_by": []
    },
    {
      "name": "wb_listora_antispam_keyword_blacklist",
      "type": "filter",
      "args_count": 4,
      "args_signature": [
        "mixed $patterns",
        "mixed $default_patterns",
        "mixed $haystack",
        "mixed $context"
      ],
      "where": "includes/class-anti-spam.php:125",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_antispam_max_urls",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $max",
        "mixed $haystack",
        "mixed $context",
        "mixed $matches",
        "mixed $url_count"
      ],
      "where": "includes/class-anti-spam.php:173",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_antispam_should_check",
      "type": "filter",
      "args_count": 4,
      "args_signature": [
        "mixed $should_check",
        "mixed $context",
        "mixed $blacklist_result",
        "mixed $url_result"
      ],
      "where": "includes/class-anti-spam.php:68",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_app_config",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array|mixed $data"
      ],
      "where": "includes/rest/class-settings-controller.php:327",
      "purpose": "Frontend app configuration",
      "consumed_by": []
    },
    {
      "name": "wb_listora_appointment_button",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($detail_type_slug) $detail_type_slug"
      ],
      "where": "templates/blocks/listing-detail/sidebar.php:79",
      "purpose": "Sidebar/appointment section rendering",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_add_favorite",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $listing_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-favorites-controller.php:205",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_calendar",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-calendar/render.php:190",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_card",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card.php:43",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_card_actions",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card-actions.php:18",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_card_content",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card-content.php:31",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_card_image",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-card/card-image.php:27",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_categories_grid",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-categories/render.php:82",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_create_listing",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "mixed($title) $title",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-submission-controller.php:405",
      "purpose": "Pre-action hook for modification",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/core/class-listing-limits.php:50"
        }
      ]
    },
    {
      "name": "wb_listora_before_create_review",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $listing_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:455",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_create_service",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array|mixed $data"
      ],
      "where": "includes/core/class-services.php:117",
      "purpose": "Pre-action hook for modification",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-services-pro.php:51",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_before_dashboard_claims",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-claims.php:36",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_dashboard_credits",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-credits.php:24",
      "purpose": "Pre-action hook for modification",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:72",
          "callback": "Pricing_Plans (plan summary panel)"
        }
      ]
    },
    {
      "name": "wb_listora_before_dashboard_listings",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-listings.php:24",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_dashboard_nav",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/nav.php:29",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_dashboard_profile",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-profile.php:19",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_dashboard_reviews",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-reviews.php:20",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_delete_listing",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $post_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-listings-controller.php:843",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_delete_review",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $review_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:649",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_delete_service",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "int $service_id"
      ],
      "where": "includes/core/class-services.php:316",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_detail_gallery",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-detail/gallery.php:26",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_detail_sidebar",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-detail/sidebar.php:24",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_detail_tabs",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-detail/tabs.php:39",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_feature_listing",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $post_id",
        "mixed($context) $context"
      ],
      "where": "includes/core/class-featured.php:156",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_featured_listings",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($featured_block_attributes) $featured_block_attributes"
      ],
      "where": "blocks/listing-featured/render.php:75",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_listing_card",
      "type": "action",
      "args_count": 5,
      "args_signature": [
        "mixed $id",
        "mixed $layout",
        "mixed $show_rating",
        "mixed $show_favorite",
        "mixed $show_type"
      ],
      "where": "blocks/listing-card/render.php:174",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_listing_grid",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($grid_block_attributes) $grid_block_attributes"
      ],
      "where": "blocks/listing-grid/render.php:209",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_map",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-map/render.php:135",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_remove_favorite",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $listing_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-favorites-controller.php:290",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_renew_listing",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $post_id",
        "mixed($context) $context"
      ],
      "where": "includes/rest/class-listings-controller.php:1469",
      "purpose": "Pre-action hook for modification",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:38",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_before_reviews",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($view_data) $view_data"
      ],
      "where": "templates/blocks/listing-reviews/reviews.php:31",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_submit_claim",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $listing_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-claims-controller.php:169",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_template",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "mixed($template_name) $template_name",
        "mixed($template_path) $template_path",
        "array $args"
      ],
      "where": "includes/class-template-helpers.php:87",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_unfeature_listing",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $post_id",
        "mixed($context) $context"
      ],
      "where": "includes/core/class-featured.php:214",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_update_claim",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $claim_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-claims-controller.php:481",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_update_listing",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $post_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-submission-controller.php:584",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_update_review",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "int $review_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:573",
      "purpose": "Pre-action hook for modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_update_service",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "array|mixed $data",
        "int $service_id"
      ],
      "where": "includes/core/class-services.php:227",
      "purpose": "Pre-action hook for modification",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-services-pro.php:52",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_calendar_events",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($events) $events",
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-calendar/render.php:125",
      "purpose": "Calendar view rendering",
      "consumed_by": []
    },
    {
      "name": "wb_listora_captcha_bypass",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($bypass) $bypass",
        "mixed($provider) $provider"
      ],
      "where": "includes/class-captcha.php:144",
      "purpose": "CAPTCHA handling",
      "consumed_by": []
    },
    {
      "name": "wb_listora_card_actions",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int|string $id"
      ],
      "where": "templates/blocks/listing-card/card-actions.php:27",
      "purpose": "Card action buttons rendering",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-comparison.php:60",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-quick-view.php:32",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-verification.php:35",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_card_view_data",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($card_data) $card_data",
        "int $post_id",
        "WP_Post|int $post"
      ],
      "where": "includes/class-template-helpers.php:517",
      "purpose": "Card data transformation",
      "consumed_by": []
    },
    {
      "name": "wb_listora_category_card_data",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "array",
        "mixed($cat) $cat"
      ],
      "where": "templates/blocks/listing-categories/categories.php:49",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_claim_approved",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $claim_id",
        "int $listing_id",
        "mixed($claimant) $claimant"
      ],
      "where": "includes/rest/class-claims-controller.php:531",
      "purpose": "Admin approval workflow",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:61"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-buddy-press-integration.php:247",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-buddy-press-integration.php:74",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_claim_rejected",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $claim_id",
        "int"
      ],
      "where": "includes/rest/class-claims-controller.php:539",
      "purpose": "Admin approval workflow",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:62"
        }
      ]
    },
    {
      "name": "wb_listora_claim_submitted",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $claim_id",
        "int $listing_id",
        "int $user_id"
      ],
      "where": "includes/rest/class-claims-controller.php:210",
      "purpose": "Submission event lifecycle",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:60"
        }
      ]
    },
    {
      "name": "wb_listora_contact_form_email_headers",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "array $headers",
        "WP_Post $post"
      ],
      "where": "includes/class-contact-form.php:239",
      "consumed_by": []
    },
    {
      "name": "wb_listora_contact_form_per_listing_daily_cap",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "int $cap",
        "int $listing_id"
      ],
      "where": "includes/class-contact-form.php:198",
      "consumed_by": []
    },
    {
      "name": "wb_listora_credits_purchase_url",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($override) $override"
      ],
      "where": "wb-listora.php:198",
      "purpose": "URL path/redirect customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_dashboard_header_actions",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "mixed $user_id",
        "mixed $user",
        "mixed $default_tab"
      ],
      "where": "blocks/user-dashboard/render.php:530",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-reverse-listings.php:75",
          "callback": "Reverse_Listings (post-a-need CTA)"
        }
      ]
    },
    {
      "name": "wb_listora_dashboard_nav_items",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $user_id"
      ],
      "where": "templates/blocks/user-dashboard/nav.php:109",
      "purpose": "Dashboard navigation customization",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-advanced-search.php:50",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-analytics.php:72",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-needs-dashboard-tab.php:34",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_dashboard_sections",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $user_id"
      ],
      "where": "blocks/user-dashboard/render.php:660",
      "purpose": "Dashboard section rendering",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-advanced-search.php:51",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-analytics.php:73",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-needs-dashboard-tab.php:35",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_dashboard_url",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($default) $default"
      ],
      "where": "includes/class-template-helpers.php:236",
      "purpose": "Dashboard section rendering",
      "consumed_by": []
    },
    {
      "name": "wb_listora_default_features",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($defaults) $defaults"
      ],
      "where": "includes/class-features.php:120",
      "purpose": "Featured listing lifecycle",
      "consumed_by": []
    },
    {
      "name": "wb_listora_detail_actions",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $post_id"
      ],
      "where": "blocks/listing-detail/render.php:340",
      "purpose": "Detail page rendering",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-comparison.php:61",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_detail_owner_bar_actions",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "mixed $breadcrumbs",
        "mixed $i",
        "mixed $crumb"
      ],
      "where": "blocks/listing-detail/render.php:381",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_detail_reviews_limit",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "int",
        "int $post_id"
      ],
      "where": "blocks/listing-detail/render.php:424",
      "purpose": "Review submission/management",
      "consumed_by": []
    },
    {
      "name": "wb_listora_detail_tabs_view_data",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($tabs_view_data) $tabs_view_data",
        "int $post_id"
      ],
      "where": "blocks/listing-detail/render.php:479",
      "purpose": "Detail page rendering",
      "consumed_by": []
    },
    {
      "name": "wb_listora_directory_url",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($default) $default"
      ],
      "where": "includes/class-template-helpers.php:188",
      "purpose": "URL path/redirect customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_draft_reminder",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $post_id"
      ],
      "where": "includes/workflow/class-expiration-cron.php:210",
      "purpose": "Plugin extension hook",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:65"
        }
      ]
    },
    {
      "name": "wb_listora_edit_auto_single_form",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $auto_single",
        "mixed $edit_listing_id",
        "mixed $layout_mode",
        "mixed $visibility_classes",
        "mixed $attributes"
      ],
      "where": "blocks/listing-submission/render.php:287",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_content",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($body) $body",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:907",
      "purpose": "Email body content customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_content_{$event}",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $body",
        "mixed $event",
        "mixed $vars",
        "mixed $to",
        "mixed $headers"
      ],
      "where": "includes/workflow/class-notifications.php:1099",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_footer_text",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "string",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:881",
      "purpose": "Email rendering customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_from_address",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:941",
      "purpose": "Email rendering customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_from_name",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($site_name) $site_name",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:933",
      "purpose": "Email rendering customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_headers",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($headers) $headers",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:949",
      "purpose": "Email rendering customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_logo_url",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "string",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:870",
      "purpose": "Email rendering customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_palette",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array"
      ],
      "where": "includes/workflow/class-notifications.php:1064",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_subject",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($subject) $subject",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:891",
      "purpose": "Email subject customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_email_subject_{$event}",
      "type": "filter",
      "args_count": 4,
      "args_signature": [
        "mixed $subject",
        "mixed $event",
        "mixed $vars",
        "mixed $body"
      ],
      "where": "includes/workflow/class-notifications.php:1084",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_expired_listing_notice",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($message) $message",
        "mixed"
      ],
      "where": "includes/class-plugin.php:432",
      "purpose": "Listing expiration handling",
      "consumed_by": []
    },
    {
      "name": "wb_listora_favorite_added",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $listing_id",
        "int $user_id"
      ],
      "where": "includes/rest/class-favorites-controller.php:249",
      "purpose": "Favorite listing operations",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-analytics.php:56",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_favorite_removed",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $listing_id",
        "int $user_id"
      ],
      "where": "includes/rest/class-favorites-controller.php:307",
      "purpose": "Favorite listing operations",
      "consumed_by": []
    },
    {
      "name": "wb_listora_feature_duration_days",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($days) $days",
        "int $post_id"
      ],
      "where": "includes/core/class-featured.php:140",
      "purpose": "Feature duration customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_feature_{$key}_enabled",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed $key",
        "mixed $enabled",
        "mixed $features"
      ],
      "where": "includes/class-features.php:182",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_featured_query_args",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($featured_q_args) $featured_q_args",
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-featured/render.php:30",
      "purpose": "Database query modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_features_registry",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($registry) $registry"
      ],
      "where": "includes/class-features.php:99",
      "purpose": "Featured listing lifecycle",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:76",
          "callback": "Pro_Plugin::register_pro_features_on_free_screen"
        }
      ]
    },
    {
      "name": "wb_listora_field_default_descriptions",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $default_descriptions",
        "mixed $key",
        "mixed $description",
        "mixed $type",
        "mixed $style"
      ],
      "where": "includes/submission-field-renderer.php:76",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_field_sanitize_callbacks",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($callbacks) $callbacks"
      ],
      "where": "includes/core/class-field.php:247",
      "purpose": "Field sanitization callbacks",
      "consumed_by": []
    },
    {
      "name": "wb_listora_field_types",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($types) $types"
      ],
      "where": "includes/core/class-field-registry.php:208",
      "purpose": "Form field handling",
      "consumed_by": []
    },
    {
      "name": "wb_listora_fullwidth_blocks",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed",
        "WP_Post|int $post"
      ],
      "where": "includes/core/class-theme-defenses.php:77",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_grid_after_card",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "mixed($listing['id']) $listing['id']",
        "mixed($grid_block_attributes) $grid_block_attributes"
      ],
      "where": "templates/blocks/listing-grid/grid.php:71",
      "purpose": "Grid view card post-rendering",
      "consumed_by": []
    },
    {
      "name": "wb_listora_grid_query_args",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($search_args) $search_args",
        "mixed($attributes) $attributes"
      ],
      "where": "blocks/listing-grid/render.php:95",
      "purpose": "Database query modification",
      "consumed_by": []
    },
    {
      "name": "wb_listora_has_payment_gateway",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $has_payment_gateway",
        "mixed $user_id",
        "mixed $credit_mappings",
        "mixed $map",
        "mixed $pack"
      ],
      "where": "blocks/user-dashboard/render.php:300",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_is_admin_screen",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed $is_listora",
        "mixed $screen"
      ],
      "where": "includes/class-template-helpers.php:748",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_is_verified",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "bool $verified",
        "int $post_id"
      ],
      "where": "includes/class-features.php:232",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php (gate_verified_on_feature)"
        }
      ]
    },
    {
      "name": "wb_listora_list_page_slugs",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed $list_pages"
      ],
      "where": "includes/admin/class-admin.php:213",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_claimed",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $listing_id",
        "array $context"
      ],
      "where": "includes/rest/class-claims-controller.php:512",
      "purpose": "Post-action hook fired after Free writes _listora_is_claimed; Pro listens to sync search-index is_claimed column (INV-12.1).",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-verification.php:42",
          "kind": "add_action"
        }
      ]
    },
    {
      "name": "wb_listora_listing_expiration_date",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "string $expiry_iso",
        "int $post_id",
        "array $context"
      ],
      "where": "includes/workflow/class-status-manager.php:99,118; includes/rest/class-listings-controller.php:1654",
      "purpose": "Pre-write filter on _listora_expiration_date so Pro can override with plan-derived expiry without owning the meta key (INV-12.2).",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:46",
          "kind": "add_filter"
        }
      ]
    },
    {
      "name": "wb_listora_listing_expired",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $post_id"
      ],
      "where": "includes/workflow/class-expiration-cron.php:169",
      "purpose": "Listing expiration handling",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:164",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_listing_expiring",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int",
        "mixed($days) $days"
      ],
      "where": "includes/admin/class-listing-columns.php:524",
      "purpose": "Plugin extension hook",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:44"
        }
      ]
    },
    {
      "name": "wb_listora_listing_indexed",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $post_id"
      ],
      "where": "includes/search/class-search-indexer.php:224",
      "purpose": "Search index updates",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_limit_counted_statuses",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array"
      ],
      "where": "includes/core/class-listing-limits.php:430",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_limit_overflow",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $user_id",
        "mixed($overflow_cost) $overflow_cost"
      ],
      "where": "includes/core/class-listing-limits.php:255",
      "purpose": "User listing limit overflow handling",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_pending_admin",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $post_id"
      ],
      "where": "includes/admin/class-listing-columns.php:472",
      "purpose": "Plugin extension hook",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:50"
        }
      ]
    },
    {
      "name": "wb_listora_listing_renewed",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $post_id"
      ],
      "where": "includes/rest/class-listings-controller.php:1572",
      "purpose": "Listing renewal completion",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:47"
        }
      ]
    },
    {
      "name": "wb_listora_listing_reported",
      "type": "action",
      "args_count": 4,
      "args_signature": [
        "mixed $listing_id",
        "mixed $report",
        "mixed $reports",
        "mixed $request"
      ],
      "where": "includes/rest/class-listings-controller.php:1387",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_reports_cleared",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed $post_id"
      ],
      "where": "includes/admin/class-report-metabox.php:185",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_status_changed",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "WP_Post|int $post->ID",
        "mixed($new) $new",
        "mixed($old) $old"
      ],
      "where": "includes/search/class-search-indexer.php:553",
      "purpose": "Listing status change event",
      "consumed_by": [
        {
          "plugin": "wb-listora",
          "where": "includes/workflow/class-notifications.php:45",
          "kind": "action_listener",
          "note": "F1 (commit 0aa62ca): canonical lifecycle-email dispatcher on_listing_status_changed; replaces 3 prior typo-listeners that fired nothing."
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:156",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_listing_submitted",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $post_id",
        "mixed($new_status) $new_status",
        "mixed($synthetic_request) $synthetic_request"
      ],
      "where": "includes/admin/class-listing-columns.php:470",
      "purpose": "Submission event lifecycle",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:36"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:207",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-buddy-press-integration.php:68",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-moderator.php:87",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:35",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_listing_title_badges",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($type ? $type->get_slug() : '') $type ? $type->get_slug() : ''"
      ],
      "where": "blocks/listing-detail/render.php:275",
      "purpose": "Hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-badges.php:158",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_listing_trashed",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed"
      ],
      "where": "includes/rest/class-listings-controller.php:868",
      "purpose": "Listing trash action",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_updated",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $post_id",
        "mixed",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-submission-controller.php:668",
      "purpose": "Plugin extension hook",
      "consumed_by": []
    },
    {
      "name": "wb_listora_listing_verify_email",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($token) $token"
      ],
      "where": "includes/workflow/class-email-verification.php:223",
      "purpose": "Email rendering customization",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:68"
        }
      ]
    },
    {
      "name": "wb_listora_listing_{$new_status}",
      "type": "action",
      "args_count": 5,
      "args_signature": [
        "mixed $new_status",
        "mixed $old_status",
        "mixed $post_id",
        "mixed $registry",
        "mixed $type"
      ],
      "where": "includes/workflow/class-status-manager.php:98",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_loaded",
      "type": "action",
      "args_count": 0,
      "args_signature": [],
      "where": "includes/class-plugin.php:49",
      "purpose": "Plugin initialization complete",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "wb-listora-pro.php:125",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_locate_template",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($template) $template",
        "mixed($template_name) $template_name",
        "mixed($template_path) $template_path"
      ],
      "where": "includes/class-template-helpers.php:51",
      "purpose": "Template file location",
      "consumed_by": []
    },
    {
      "name": "wb_listora_login_modal_register_url",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "string $url",
        "int $listing_id",
        "string $current_permalink"
      ],
      "where": "blocks/listing-detail/render.php:801",
      "consumed_by": []
    },
    {
      "name": "wb_listora_map_config",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($map_config) $map_config"
      ],
      "where": "blocks/listing-map/render.php:113",
      "purpose": "Map view rendering",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-google-maps.php:50",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_map_provider",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "string $value"
      ],
      "where": "wb-listora.php:288",
      "purpose": "Resolve the map provider setting; documented Pro extension point (plans/free/11-maps.md, plans/free/41-free-vs-pro-definitive.md). Fired only when settings key is map_provider.",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-google-maps.php:41",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_member_profile_url",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $user_profile_url",
        "mixed $user_id",
        "mixed $review_data",
        "mixed $row",
        "mixed $user"
      ],
      "where": "includes/rest/class-reviews-controller.php:343",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-buddy-press-integration.php:851",
          "callback": "BuddyPress_Integration::filter_member_profile_url",
          "args_count": 3
        }
      ]
    },
    {
      "name": "wb_listora_notification_log_enabled",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "bool"
      ],
      "where": "includes/workflow/class-notifications.php:1010",
      "purpose": "Notification logging control",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:1000"
        }
      ]
    },
    {
      "name": "wb_listora_notification_recipients",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($to) $to",
        "mixed($event) $event",
        "mixed($vars) $vars"
      ],
      "where": "includes/workflow/class-notifications.php:922",
      "purpose": "Notification recipient filtering",
      "consumed_by": []
    },
    {
      "name": "wb_listora_notification_skipped",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "mixed($event_key) $event_key",
        "string",
        "mixed($context) $context"
      ],
      "where": "includes/workflow/class-notifications.php:668",
      "purpose": "Notification skip conditions",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "tools/verify-notifications.php:79"
        },
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "tools/verify-notifications.php:101"
        }
      ]
    },
    {
      "name": "wb_listora_page_id",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed $id",
        "mixed $key",
        "mixed $context"
      ],
      "where": "includes/core/class-page-registry.php:138",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_page_url",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $url",
        "mixed $key",
        "mixed $args",
        "mixed $id",
        "mixed $out"
      ],
      "where": "includes/core/class-page-registry.php:190",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_placeholder_url",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($url) $url"
      ],
      "where": "includes/class-template-helpers.php:129",
      "purpose": "URL path/redirect customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_pro_cta_should_show",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "bool",
        "mixed($surface) $surface"
      ],
      "where": "includes/admin/class-pro-promotion.php:139",
      "purpose": "Pro upgrade prompts",
      "consumed_by": []
    },
    {
      "name": "wb_listora_rate_limit_bypass",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "bool",
        "mixed($action) $action",
        "int"
      ],
      "where": "includes/class-rate-limiter.php:137",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_rate_limit_config",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($config) $config",
        "mixed($action) $action"
      ],
      "where": "includes/class-rate-limiter.php:188",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_register_field_types",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($this) $this"
      ],
      "where": "includes/core/class-field-registry.php:54",
      "purpose": "Registry initialization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_register_listing_types",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($this) $this"
      ],
      "where": "includes/core/class-listing-type-registry.php:78",
      "purpose": "Registry initialization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_register_pages",
      "type": "action",
      "args_count": 0,
      "args_signature": [],
      "where": "includes/page-registry-helpers.php:269",
      "purpose": "Extension hook fired after Free registers its 3 canonical pages — consumers (Pro / themes) hook here and call wb_listora_register_page() instead of touching Page_Registry::register directly. Closes architecture invariant INV-3.",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:56",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_render_contact_form",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "bool $should_render"
      ],
      "where": "includes/class-contact-form.php:56",
      "consumed_by": [
        "self — internal gate based on Pro lead_form toggle state"
      ]
    },
    {
      "name": "wb_listora_renewal_cost",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($cost) $cost",
        "int $post_id",
        "int $plan_id"
      ],
      "where": "includes/rest/class-listings-controller.php:1335",
      "purpose": "Listing renewal pricing",
      "consumed_by": []
    },
    {
      "name": "wb_listora_renewal_duration_days",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($duration_days) $duration_days",
        "int $post_id",
        "int $plan_id"
      ],
      "where": "includes/rest/class-listings-controller.php:1338",
      "purpose": "Listing renewal pricing",
      "consumed_by": []
    },
    {
      "name": "wb_listora_reset_option_keys",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array $option_keys"
      ],
      "where": "includes/rest/class-settings-controller.php:360",
      "purpose": "Filters the list of option keys that the Reset Settings endpoint will purge. Pro adds Pro-specific option keys so Reset is comprehensive.",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:46",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_rest_api_init",
      "type": "action",
      "args_count": 0,
      "args_signature": [],
      "where": "includes/class-plugin.php:251",
      "purpose": "REST API functionality",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:105",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-advanced-search.php:37",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-analytics.php:59",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:60",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-badges.php:167",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-comparison.php:59",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-google-places.php:42",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-lead-form.php:33",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-moderator.php:99",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:94",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-photo-reviews.php:28",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:50",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-reverse-listings.php:47",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-services-pro.php:58",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_rest_listing_response",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($listing) $listing",
        "WP_Post|int $post"
      ],
      "where": "includes/rest/class-search-controller.php:461",
      "purpose": "REST API functionality",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-badges.php:152",
          "kind": "filter_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-multi-criteria-reviews.php:35",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_rest_prepare_claim",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($response_data) $response_data",
        "int $claim_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-claims-controller.php:238",
      "purpose": "Claim submission and approval",
      "consumed_by": []
    },
    {
      "name": "wb_listora_rest_prepare_dashboard_stats",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "array|mixed $data",
        "int $user_id",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-dashboard-controller.php:284",
      "purpose": "Dashboard section rendering",
      "consumed_by": []
    },
    {
      "name": "wb_listora_rest_prepare_favorite",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($fav_data) $fav_data",
        "int",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-favorites-controller.php:155",
      "purpose": "Favorite listing operations",
      "consumed_by": []
    },
    {
      "name": "wb_listora_rest_prepare_listing",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "array|mixed $data",
        "WP_Post|int $post",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-listings-controller.php:777",
      "purpose": "REST API response data",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-badges.php:149",
          "kind": "filter_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-quick-view.php:41",
          "kind": "filter_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-verification.php:39",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_rest_prepare_listing_type",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($type_data) $type_data",
        "mixed($type) $type",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-listing-types-controller.php:152",
      "purpose": "REST API response data",
      "consumed_by": []
    },
    {
      "name": "wb_listora_rest_prepare_review",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($review_data) $review_data",
        "int",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:342",
      "purpose": "Review submission/management",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-multi-criteria-reviews.php:39",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_rest_prepare_search_result",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($response_data) $response_data",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-search-controller.php:290",
      "purpose": "Search results processing",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-infinite-scroll.php:72",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_rest_prepare_service",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "array|mixed $data",
        "int",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-services-controller.php:421",
      "purpose": "Service CRUD operations",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-services-pro.php:48",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_review_after_content",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($review) $review"
      ],
      "where": "templates/blocks/listing-reviews/review-card.php:54",
      "purpose": "Review submission/management",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-photo-reviews.php:37",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_review_criteria",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "array",
        "mixed($listing_type_slug) $listing_type_slug"
      ],
      "where": "blocks/listing-reviews/render.php:78",
      "purpose": "Review rating criteria configuration",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-multi-criteria-reviews.php:29",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_review_form_after_content",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $post_id"
      ],
      "where": "templates/blocks/listing-detail/tabs.php:399",
      "purpose": "Review form content injection",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-photo-reviews.php:34",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_review_helpful_milestone",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $review_id",
        "mixed($new_count) $new_count"
      ],
      "where": "includes/rest/class-reviews-controller.php:772",
      "purpose": "Review helpful vote milestone",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:57"
        }
      ]
    },
    {
      "name": "wb_listora_review_reply",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $review_id"
      ],
      "where": "includes/rest/class-reviews-controller.php:807",
      "purpose": "Review reply submission",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:54"
        }
      ]
    },
    {
      "name": "wb_listora_review_status_changed",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $review_id",
        "string $status",
        "int $listing_id"
      ],
      "where": "includes/rest/class-reviews-controller.php:650",
      "purpose": "Fires when a review's moderation status changes (pending/approved/rejected). Lets notifications, badges, and Pro extensions react to lifecycle.",
      "consumed_by": []
    },
    {
      "name": "wb_listora_review_submitted",
      "type": "action",
      "args_count": 6,
      "args_signature": [
        "int $review_id",
        "int $listing_id",
        "int $user_id",
        "mixed($criteria_ratings) $criteria_ratings",
        "mixed($review_photos) $review_photos",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-reviews-controller.php:524",
      "purpose": "Submission event lifecycle",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/workflow/class-notifications.php:53"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-audit-log.php:210",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-buddy-press-integration.php:241",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-buddy-press-integration.php:71",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-multi-criteria-reviews.php:32",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-outgoing-webhooks.php:167",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-photo-reviews.php:31",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_schema_data",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "array|mixed $data",
        "int $this->post_id"
      ],
      "where": "includes/schema/class-schema-generator.php:166",
      "purpose": "Schema.org structured data",
      "consumed_by": []
    },
    {
      "name": "wb_listora_search_after_form",
      "type": "action",
      "args_count": 5,
      "args_signature": [
        "mixed $layout",
        "mixed $listing_type",
        "mixed $search_url_keyword",
        "mixed $search_url_type",
        "mixed $search_url_location"
      ],
      "where": "blocks/listing-search/render.php:210",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_search_args",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "array $args",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-search-controller.php:252",
      "purpose": "Search query modification",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-verification.php:32",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_search_before_form",
      "type": "action",
      "args_count": 5,
      "args_signature": [
        "mixed $layout",
        "mixed $listing_type",
        "mixed $search_url_keyword",
        "mixed $search_url_type",
        "mixed $search_url_location"
      ],
      "where": "blocks/listing-search/render.php:190",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_search_resolved",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "array $args",
        "int $total",
        "array $context"
      ],
      "where": "includes/search/class-search-engine.php:210",
      "purpose": "Fires after every search query resolves (REST + SSR/block paths) so Pro search-analytics can observe resolved queries with no coupling. Read-only; distinct from the wb_listora_search_results REST FILTER.",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-search-analytics.php:52",
          "callback": "Search_Analytics::record_search",
          "args_count": 3
        }
      ]
    },
    {
      "name": "wb_listora_search_resolved_context",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "array $context",
        "array $args",
        "array $result"
      ],
      "where": "includes/search/class-search-engine.php:181",
      "purpose": "Filters the context array (source, paging, result_count) accompanying a resolved search query before wb_listora_search_resolved fires.",
      "consumed_by": []
    },
    {
      "name": "wb_listora_search_results",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($response_data) $response_data",
        "array $args",
        "WP_REST_Request $request"
      ],
      "where": "includes/rest/class-search-controller.php:282",
      "purpose": "Search results processing",
      "consumed_by": []
    },
    {
      "name": "wb_listora_send_notification",
      "type": "filter",
      "args_count": 4,
      "args_signature": [
        "bool",
        "mixed($event) $event",
        "mixed($vars) $vars",
        "string($to) $to"
      ],
      "where": "includes/workflow/class-notifications.php:840",
      "purpose": "Notification dispatch control",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-notification-digest.php:180",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_settings_nav_groups",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($groups) $groups"
      ],
      "where": "includes/admin/class-settings-page.php:288",
      "purpose": "Settings and configuration",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:136",
          "kind": "filter_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:238",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_settings_skip_form_tabs",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array"
      ],
      "where": "includes/admin/class-settings-page.php:377",
      "purpose": "Tab navigation rendering",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:224",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_settings_tab_content",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $tab_id"
      ],
      "where": "includes/admin/class-settings-page.php:469",
      "purpose": "Settings tab content",
      "consumed_by": [
        {
          "plugin": "unknown",
          "where": "",
          "kind": "legacy_entry",
          "raw": "includes/admin/class-pro-promotion.php:104"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:260",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-infinite-scroll.php:49",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-seo-pages.php:103",
          "kind": "action_listener"
        },
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-seo-pages.php:71",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_settings_tab_content_after_form",
      "type": "action",
      "args_count": 5,
      "args_signature": [
        "mixed $tab_id",
        "mixed $skip_form_tabs",
        "mixed $groups",
        "mixed $group",
        "mixed $tab"
      ],
      "where": "includes/admin/class-settings-page.php:565",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:492",
          "callback": "closure (settings_errors for credits/needs tabs)"
        }
      ]
    },
    {
      "name": "wb_listora_settings_tabs",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($tabs) $tabs"
      ],
      "where": "includes/admin/class-settings-page.php:311",
      "purpose": "Tab navigation rendering",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:248",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_skip_admin_header",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $screen",
        "mixed $submenu",
        "mixed $title",
        "mixed $plugin",
        "mixed $_GET"
      ],
      "where": "includes/admin/class-admin.php:2057",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_submission_captcha",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $form_id"
      ],
      "where": "includes/class-captcha.php:106",
      "purpose": "CAPTCHA handling",
      "consumed_by": []
    },
    {
      "name": "wb_listora_submission_login_buttons",
      "type": "action",
      "args_count": 0,
      "args_signature": [],
      "where": "templates/blocks/listing-submission/submission.php:67",
      "purpose": "Login button customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_submission_plan_step",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed($listing_type) $listing_type"
      ],
      "where": "templates/blocks/listing-submission/submission.php:111",
      "purpose": "Plugin extension hook",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:42",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_submission_register_url",
      "type": "filter",
      "args_count": 4,
      "args_signature": [
        "mixed $submission_register_url",
        "mixed $submission_current_permalink",
        "mixed $wrapper_attrs",
        "mixed $submission_login_url"
      ],
      "where": "blocks/listing-submission/render.php:125",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_submission_steps",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "mixed($steps) $steps",
        "mixed($listing_type) $listing_type",
        "mixed($is_edit_mode) $is_edit_mode"
      ],
      "where": "blocks/listing-submission/render.php:165",
      "purpose": "Hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-pricing-plans.php:47",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_submit_url",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($default) $default"
      ],
      "where": "includes/class-template-helpers.php:211",
      "purpose": "Submission event lifecycle",
      "consumed_by": []
    },
    {
      "name": "wb_listora_template_args",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "array $args",
        "mixed($template_name) $template_name"
      ],
      "where": "includes/class-template-helpers.php:81",
      "purpose": "Template argument passing",
      "consumed_by": []
    },
    {
      "name": "wb_listora_theme_bridges",
      "type": "filter",
      "args_count": 5,
      "args_signature": [
        "mixed $bridges",
        "mixed $bridge_slug",
        "mixed $child_theme",
        "mixed $active_theme",
        "mixed $bridge_path"
      ],
      "where": "includes/class-assets.php:100",
      "purpose": "Hook for extension (auto-added via manifest refresh 2026-05-21)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_trust_proxy_headers",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "bool"
      ],
      "where": "includes/class-rate-limiter.php:227",
      "purpose": "Hook for extension",
      "consumed_by": []
    },
    {
      "name": "wb_listora_unverified_listing_cleaned",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $post_id",
        "mixed($action) $action"
      ],
      "where": "includes/workflow/class-email-verification.php:544",
      "purpose": "Cleanup operation completion",
      "consumed_by": []
    },
    {
      "name": "wb_listora_upgrade_url",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "mixed($default) $default"
      ],
      "where": "includes/class-template-helpers.php:258",
      "purpose": "URL path/redirect customization",
      "consumed_by": []
    },
    {
      "name": "wb_listora_user_credit_balance",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($balance) $balance",
        "int $user_id"
      ],
      "where": "includes/core/class-listing-limits.php:554",
      "purpose": "Credit system management",
      "consumed_by": [
        {
          "plugin": "wb-listora.php:418",
          "where": "",
          "kind": "legacy_entry",
          "raw": "wb-listora.php:418"
        }
      ]
    },
    {
      "name": "wb_listora_user_listing_limit",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "mixed($best) $best",
        "int $user_id"
      ],
      "where": "includes/core/class-listing-limits.php:382",
      "purpose": "User limits and quotas",
      "consumed_by": []
    },
    {
      "name": "wb_listora_webhook_secret",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "string $default",
        "array $context"
      ],
      "where": "includes/admin/class-settings-page.php:998",
      "purpose": "Filter for the webhook signing secret so Free does not read Pro's wb_listora_pro_webhook_secret option directly (INV-12.4).",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-webhook-receiver.php:46",
          "kind": "add_filter"
        }
      ]
    },
    {
      "name": "wb_listora_daily_cleanup",
      "type": "action",
      "args_count": 0,
      "args_signature": [],
      "where": "includes/class-cli-commands.php:273",
      "purpose": "Extension point fired by the `wp listora cleanup` subcommand so Pro/site code can hook scheduled-style cleanup into the manual CLI sweep.",
      "consumed_by": []
    },
    {
      "name": "wb_listora_save_features_extra",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "array $input"
      ],
      "where": "includes/admin/class-settings-page.php:2342",
      "purpose": "Fires after Free saves its Features screen so Pro can persist its own feature toggles merged into the same screen (BG-4).",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:439",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_demo_image_timeout",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "int $timeout",
        "string $url"
      ],
      "where": "demo/class-demo-seeder.php:558",
      "purpose": "Filter the per-image download timeout used by the demo seeder (default 10s).",
      "consumed_by": []
    },
    {
      "name": "wb_listora_demo_gallery_max",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "int $max",
        "string $type"
      ],
      "where": "demo/class-demo-seeder.php:663",
      "purpose": "Filter the max gallery image count seeded per demo listing type.",
      "consumed_by": []
    },
    {
      "name": "wb_listora_docs_url",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "string $url",
        "string $tab_id",
        "string $section"
      ],
      "where": "includes/admin/class-settings-page.php:377",
      "purpose": "Filter the per-tab/per-section documentation URL surfaced by settings doc buttons.",
      "consumed_by": []
    },
    {
      "name": "wb_listora_features_category_labels",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array $labels"
      ],
      "where": "includes/class-features.php:178",
      "purpose": "Filter the Features-screen category labels so Pro can register its own feature-category headings (BG-4).",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:67",
          "kind": "filter_listener"
        }
      ]
    },
    {
      "name": "wb_listora_seo_plugin_active",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "bool $active"
      ],
      "where": "includes/class-features.php:354",
      "purpose": "Canonical SEO-plugin detector so Listora defers schema/meta output to Yoast/Rank Math and never double-injects (M9/M10 SEO fixes).",
      "consumed_by": []
    },
    {
      "name": "wbcom_credits_sdk_registry",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "mixed"
      ],
      "where": "libs/wbcom-credits-sdk/wbcom-credits-sdk.php:184",
      "purpose": "Hook for extension",
      "consumed_by": [
        {
          "plugin": "wb-listora",
          "where": "wb-listora.php:478",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_bg_import_batch",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "string $run_id"
      ],
      "where": "includes/import-export/class-background-import.php:971",
      "purpose": "Action Scheduler single-action (group wb-listora) that the canonical Background_Import engine self-queues to process ONE chunk of an import run, then re-queues itself while rows/units remain. Re-fired from enqueue_batch via Cron_Scheduler::enqueue_async; handled by Background_Import::run_batch (bound on init, class-background-import.php:122). Resumable: reads the persisted cursor so an AS retry continues from the last committed offset rather than restarting.",
      "consumed_by": [
        {
          "plugin": "wb-listora",
          "where": "includes/import-export/class-background-import.php:122",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_bg_import_finalize",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "string $run_id"
      ],
      "where": "includes/import-export/class-background-import.php:981",
      "purpose": "Action Scheduler single-action (group wb-listora) queued once a Background_Import run's source is exhausted; rebuilds the search index for the run's newly created listings, drops the stashed source file, and marks the run done. Re-fired from enqueue_finalize via Cron_Scheduler::enqueue_async; handled by Background_Import::run_finalize (bound on init, class-background-import.php:123).",
      "consumed_by": [
        {
          "plugin": "wb-listora",
          "where": "includes/import-export/class-background-import.php:123",
          "kind": "action_listener"
        }
      ]
    },
    {
      "name": "wb_listora_bg_import_use_async",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "bool $use_async",
        "array $state"
      ],
      "where": "includes/import-export/class-background-import.php:916",
      "purpose": "Filters whether a given Background_Import run executes asynchronously over Action Scheduler. Returning false forces the synchronous fallback (the canonical engine also runs inline when Action Scheduler is unavailable or the item count is at/below SYNC_THRESHOLD=10). Lets hosts opt tiny packs out of a cron round-trip or force inline draining for debugging.",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_bulk_edit",
      "type": "action",
      "args_count": 4,
      "args_signature": [
        "string $action",
        "int $ok",
        "int $failed",
        "int[] $ids"
      ],
      "where": "includes/admin/class-listing-bulk-actions.php:212",
      "purpose": "Fires after an admin bulk-edit action completes (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_before_dashboard_favorites",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "array $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-favorites.php:20",
      "purpose": "Extension point before the dashboard Favorites tab content (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_dashboard_favorites",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "array $view_data"
      ],
      "where": "templates/blocks/user-dashboard/tab-favorites.php:60",
      "purpose": "Extension point after the dashboard Favorites tab content (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_after_unsubscribe",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $user_id",
        "string $event"
      ],
      "where": "includes/rest/class-unsubscribe-controller.php:229",
      "purpose": "Fires after a one-click email opt-out is applied (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_dashboard_credit_row_actions",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "array $entry"
      ],
      "where": "templates/blocks/user-dashboard/tab-credits.php:349",
      "purpose": "Per-row action slot in the dashboard credit history table (1.2.0)",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-receipt.php:94",
          "callback": "Receipt::render_history_receipt_link"
        }
      ]
    },
    {
      "name": "wb_listora_demo_import_run",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "string $run_id",
        "string[] $packs"
      ],
      "where": "includes/admin/class-settings-page.php:2843",
      "purpose": "Sanctioned demo-import trigger — fired when a background demo import run is queued (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_review_reminder",
      "type": "action",
      "args_count": 2,
      "args_signature": [
        "int $listing_id",
        "int $pending_count"
      ],
      "where": "includes/workflow/class-expiration-cron.php:285",
      "purpose": "Fires per listing owner from the daily review-reminder cron; Free's own Notifications listens (1.2.0)",
      "consumed_by": [
        {
          "plugin": "wb-listora",
          "where": "includes/workflow/class-notifications.php:180",
          "callback": "Notifications::review_reminder"
        }
      ]
    },
    {
      "name": "wb_listora_view_recorded",
      "type": "action",
      "args_count": 1,
      "args_signature": [
        "int $listing_id"
      ],
      "where": "includes/features/class-analytics-lite.php:206",
      "purpose": "Fires after Analytics_Lite records a non-bot listing view (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_analytics_is_bot",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "bool $is_bot",
        "string $ua"
      ],
      "where": "includes/features/class-analytics-lite.php:351",
      "purpose": "Override bot classification for view counting (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_bot_signatures",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "string[] $signatures"
      ],
      "where": "includes/class-bot-detection.php:148",
      "purpose": "Extend/replace the UA bot-signature list (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_is_bot_request",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "bool $is_bot=false",
        "string $ua"
      ],
      "where": "includes/class-bot-detection.php:104",
      "purpose": "Short-circuit bot detection for the current request (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_privacy_erase_per_page",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "int $per_page",
        "string $email_address",
        "int $page"
      ],
      "where": "includes/privacy/class-privacy-eraser.php:80",
      "purpose": "Tune GDPR eraser batch size (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_pro_owns_analytics",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "bool $pro_owns=false"
      ],
      "where": "includes/features/class-analytics-lite.php:117",
      "purpose": "Pro supersession handshake — Pro returns true so Analytics_Lite stands down and views are not double-counted (1.2.0)",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/features/class-analytics.php:66",
          "callback": "__return_true"
        }
      ]
    },
    {
      "name": "wb_listora_repair_term_taxonomies",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "string[] $taxonomies"
      ],
      "where": "includes/import-export/class-term-helper.php:84",
      "purpose": "Taxonomies covered by the import term-repair pass (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_required_field_messages",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "array<string,string> $messages"
      ],
      "where": "includes/class-assets.php:225",
      "purpose": "Per-field validation prompts for custom-required submission fields (featured_image, gallery) localized to the submission JS (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_review_reminder_grace_hours",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "int $grace_hours=48"
      ],
      "where": "includes/workflow/class-expiration-cron.php:242",
      "purpose": "Grace window before a review reminder is sent (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_show_credits",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "bool $show"
      ],
      "where": "blocks/user-dashboard/render.php:304; blocks/listing-submission/render.php:345",
      "purpose": "Gate every customer-facing credit surface; default = Credits SDK availability. Pro hooks it to hide credit UI when the monetization toggle is off (1.2.0)",
      "consumed_by": [
        {
          "plugin": "wb-listora-pro",
          "where": "includes/class-pro-plugin.php:68",
          "callback": "Pro_Plugin::gate_credit_surfaces_on_monetization"
        }
      ]
    },
    {
      "name": "wb_listora_submission_layout_mode",
      "type": "filter",
      "args_count": 2,
      "args_signature": [
        "string $layout_mode",
        "array $attributes"
      ],
      "where": "blocks/listing-submission/render.php:52",
      "purpose": "Override the submission form layout (wizard|single_form) resolved from the submission_form_style setting (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_unsubscribable_events",
      "type": "filter",
      "args_count": 1,
      "args_signature": [
        "string[] $events"
      ],
      "where": "includes/rest/class-unsubscribe-controller.php:69",
      "purpose": "Which notification events expose a one-click unsubscribe link (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_unsubscribe_url",
      "type": "filter",
      "args_count": 3,
      "args_signature": [
        "string $url",
        "int $user_id",
        "string $event"
      ],
      "where": "includes/rest/class-unsubscribe-controller.php:116",
      "purpose": "Filter the signed one-click unsubscribe URL placed in email footers (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wpml_object_id",
      "type": "filter",
      "args_count": 4,
      "args_signature": [
        "int $id",
        "string 'page'",
        "bool true"
      ],
      "where": "includes/core/class-page-registry.php:119",
      "purpose": "Third-party API-call convention — applies WPML's documented filter to translate registered page IDs; consumed by WPML/Polylang, not a WB Listora extension surface (1.2.0)",
      "consumed_by": []
    },
    {
      "name": "wb_listora_notification_created",
      "type": "action",
      "args_count": 3,
      "args_signature": [
        "int $recipient_id",
        "string $type",
        "array $data"
      ],
      "where": "includes/workflow/class-suite-notifications.php:210",
      "purpose": "Fires whenever Listora produces a user-facing notification (recipient + ready-to-display message + deep link) so external aggregators (BuddyNext) can mirror it without re-deriving Listora's display logic. Fired by Workflow\\Suite_Notifications on listing status change, review submitted, and claim submitted/updated. Card 9994191304.",
      "consumed_by": []
    }
  ],
  "frontend_assets": {
    "js": [
      {
        "handle": "listora-confirm",
        "src": "assets/js/shared/confirm.js"
      },
      {
        "handle": "listora-submit-lock",
        "src": "assets/js/shared/submit-lock.js"
      },
      {
        "handle": "listora-i18n",
        "note": "Localization shim for Interactivity API"
      },
      {
        "handle": "listora-directory",
        "src": "assets/js/blocks/directory.js",
        "type": "module",
        "note": "Block interactivity store (viewScriptModule)"
      }
    ],
    "css": [
      {
        "handle": "listora-base",
        "src": "assets/css/listora-base.css"
      },
      {
        "handle": "listora-confirm",
        "src": "assets/css/shared/confirm.css"
      },
      {
        "handle": "listora-pro-cta",
        "src": "assets/css/shared/pro-cta.css"
      }
    ]
  },
  "cron": [
    {
      "hook": "wb_listora_check_expirations",
      "interval": "twicedaily",
      "handler": "WBListora\\Workflow\\Expiration_Cron::check_expirations"
    },
    {
      "hook": "wb_listora_draft_reminder_cron",
      "interval": "twicedaily",
      "handler": "WBListora\\Workflow\\Expiration_Cron::send_draft_reminders"
    },
    {
      "hook": "wb_listora_daily_cleanup",
      "interval": "daily",
      "handler": "WBListora\\Workflow\\Expiration_Cron::prune_analytics"
    },
    {
      "hook": "wb_listora_expire_featured",
      "interval": "daily",
      "handler": "WBListora\\Core\\Featured::expire_featured"
    },
    {
      "hook": "wb_listora_cleanup_unverified_listings",
      "interval": "daily",
      "handler": "WBListora\\Workflow\\Email_Verification::cleanup_unverified"
    },
    {
      "hook": "wb_listora_search_reindex",
      "interval": "single-event (chunked)",
      "purpose": "Background search index rebuild — chunked through wp-cron after schema bumps so live writes stay accurate while old rows are refreshed.",
      "registered_in": "Search_Indexer::register_hooks",
      "scheduled_by": "Search_Indexer::schedule_full_reindex (called from Migrator)"
    },
    {
      "hook": "wb_listora_review_reminder_cron",
      "interval": "daily",
      "handler": "WBListora\\Workflow\\Expiration_Cron::send_review_reminders",
      "scheduled_by": "Cron_Scheduler::schedule_recurring (includes/workflow/class-expiration-cron.php:33)",
      "added": "1.2.0"
    },
    {
      "hook": "wb_listora_prune_email_log",
      "interval": "daily",
      "handler": "WBListora\\Workflow\\Notifications::prune_log",
      "scheduled_by": "Cron_Scheduler::schedule_recurring with wp_schedule_event fallback (includes/workflow/class-notifications.php:1407-1411)",
      "notes": "Pre-existing manifest omission corrected in the 2026-06-10 refresh (hook predates 1.2.0)."
    },
    {
      "hook": "wb_listora_bg_import_batch",
      "interval": "async (Action Scheduler group wb-listora; wp-cron single-event fallback via Cron_Scheduler::queue)",
      "handler": "WBListora\\ImportExport\\Background_Import::run_batch",
      "scheduled_by": "Background_Import::queue_demo/queue_file per run_id",
      "added": "1.2.0"
    },
    {
      "hook": "wb_listora_bg_import_finalize",
      "interval": "async (Action Scheduler group wb-listora; wp-cron single-event fallback)",
      "handler": "WBListora\\ImportExport\\Background_Import::finalize_run",
      "scheduled_by": "Background_Import batch chain tail",
      "added": "1.2.0"
    }
  ],
  "wp_cli": [
    {
      "name": "listora",
      "handler": "WBListora\\CLI_Commands",
      "subcommands": [
        "stats",
        "reindex",
        "listing-types",
        "import",
        "export",
        "repair",
        "migrate",
        "demo",
        "test-email",
        "cleanup"
      ]
    }
  ],
  "storage_drivers": [],
  "listing_types": [
    {
      "slug": "business",
      "label": "Business"
    },
    {
      "slug": "restaurant",
      "label": "Restaurant"
    },
    {
      "slug": "real-estate",
      "label": "Real Estate"
    },
    {
      "slug": "hotel",
      "label": "Hotel"
    },
    {
      "slug": "event",
      "label": "Event"
    },
    {
      "slug": "job",
      "label": "Job"
    },
    {
      "slug": "healthcare",
      "label": "Healthcare"
    },
    {
      "slug": "education",
      "label": "Education"
    },
    {
      "slug": "place",
      "label": "Place"
    },
    {
      "slug": "classified",
      "label": "Classified"
    }
  ],
  "security": {
    "uploads_gate": "includes/rest/class-claims-controller.php (wp_handle_upload for proof files)",
    "signing_entry_points": [],
    "always_sign_filter": null,
    "rate_limit_middleware": "includes/class-captcha.php (reCAPTCHA v3 + Cloudflare Turnstile gate on submission)",
    "permission_callbacks": "All REST endpoints return WP_Error (401/403) instead of false; capability gates per route",
    "nonce_actions": [
      "listora_submit_listing",
      "listora_admin_nonce",
      "wb_listora_promo_nonce"
    ]
  },
  "ci_guards": {
    "phpstan_level": 7,
    "wpcs_standard": "WordPress",
    "ci_workflow": ".github/workflows (PHP Lint, WPCS, PHPStan L7, PHPUnit, Plugin Check)"
  },
  "coding_rules": [
    "All write operations fire before_/after_ hooks; before_ filter can return WP_Error to abort.",
    "Every REST response is filterable via wb_listora_rest_prepare_<resource> for Pro/extensions.",
    "Single Interactivity API namespace: listora/directory. All actions in src/interactivity/store.js (NOT individual view.js).",
    "Per-instance block CSS via WBListora\\Block_CSS — no global block class CSS.",
    "Themes can override templates WooCommerce-style: {theme}/wb-listora/blocks/<block>/<file>.php.",
    "Server state via wp_interactivity_state(); do NOT define client defaults for server-provided keys."
  ],
  "build_commands": {
    "release": "npm run build",
    "ci_local": "npm run lint:js && npm run lint:css && composer phpstan && composer phpcs && composer phpunit"
  },
  "generated": {
    "at": "2026-06-10T00:00:00Z",
    "from": "wp-plugin-onboard --refresh (diff-driven, 1.2.0 release wave)",
    "branch": "1.2.0",
    "schema_version": "v2.1",
    "scan_scope": "distignore+refined",
    "scan_path": ".",
    "php_file_count": 182,
    "js_file_count": 70,
    "css_file_count": 50,
    "refresh_history": [
      {
        "date": "2026-06-10",
        "type": "diff-driven refresh — 1.2.0 release wave (~121 commits since 2026-06-06)",
        "summary": "plugin.version 1.1.0 -> 1.2.0. REST 57 -> 58 (+GET /unsubscribe, Unsubscribe_Controller; import progress/queue routes were already recorded mid-wave). AJAX 4 -> 5 (+listora_run_demo_import). hooks_fired 238 -> 259 (+8 actions, +13 filters incl. show_credits, submission_layout_mode, required_field_messages, search/bot/privacy/unsubscribe surfaces, wpml_object_id third-party call). cron 6 -> 10 (+review_reminder_cron, +prune_email_log [pre-existing omission], +bg_import_batch/finalize AS jobs). interactivity shared store 74 -> 75 actions (+closeDashServices). settings: submission_form_style sub-key documented. consumed_by: +7 Pro listeners on existing hooks, 3 stale entries cleared; cross-plugin coupling pair count corrected 32 -> 69 (prior cache under-counted; full multiline rescan)."
      },
      {
        "date": "2026-06-06",
        "type": "diff-driven refresh — 1.1.0 released; +7 fired hooks from the release wave",
        "summary": "Post-release onboard refresh covering the 1.1.0 wave (2026-05-24 manifest refresh → HEAD c5826be, 94 commits: audit fixes AUD-F1..F11, BG-2/BG-3/BG-4, M4-M12 SEO/schema/a11y fixes, Credits SDK re-home from gitignored vendor/ submodule to committed composer-free libs/wbcom-credits-sdk, DUP-1 claims-model consolidation, wp-cli test-email/cleanup subcommands, perf pagination work). plugin.version 1.0.0 → 1.1.0. hooks_fired 226 → 233: +2 actions (wb_listora_daily_cleanup do_action extensibility fire in the new `wp listora cleanup` CLI subcommand @ class-cli-commands.php:273; wb_listora_save_features_extra @ class-settings-page.php:2342, consumed by Pro class-pro-plugin.php:439 for BG-4) and +5 filters (wb_listora_demo_image_timeout + wb_listora_demo_gallery_max in demo/class-demo-seeder.php from the slow-demo-import fix; wb_listora_docs_url @ class-settings-page.php:377 from the docs-buttons fix; wb_listora_features_category_labels @ class-features.php:178 consumed by Pro class-pro-plugin.php:67 for BG-4; wb_listora_seo_plugin_active @ class-features.php:354, the canonical SEO-plugin detector from the M9/M10 double-injection fix). counts.hooks_fired_actions 120 → 122, filters 106 → 111, total 226 → 233. Cross-plugin coupling +2 Free→Pro pairs (save_features_extra + features_category_labels). Net-zero REST routes (git diff added 0 / removed 0 register_rest_route in window — M4-M12 gated existing fields, did not add routes). No new AJAX, blocks, tables, capabilities, admin_pages, or own cron (the one new wp_schedule_event in the diff is inside libs/edd-sl-sdk, third-party, scoped out). wp_cli subcommands stayed 10 (test-email + cleanup were already recorded in commit 23f6a30). Fixed stale path: wbcom_credits_sdk_registry hook where vendor/wbcom-credits-sdk/wbcom-credits-sdk.php:65 → libs/wbcom-credits-sdk/wbcom-credits-sdk.php:184 + corrected its malformed consumed_by entry to wb-listora.php:478, reflecting the SDK re-home. Coverage gate: own-source ground-truth grep returned 113 do_action + 102 apply_filters unique literals (215) vs manifest 233 — the 18-name delta is dynamic hooks (wb_listora_email_content_{$event}, wb_listora_feature_{$key}_enabled, etc.), wrapper-fired and multi-line apply_filters the single-line regex misses; manifest is the superset and correct. libs/ (edd-sl-sdk + re-homed wbcom-credits-sdk) excluded from own-source counts as third-party SDKs (ship in dist but are not WB Listora's own inventory). REST own-source raw register_rest_route = 57 vs manifest 55 (2 generic batch/health registrations in class-plugin.php counted as wrappers — within documented tolerance). Released on GitHub as v1.1.0 from main; readme.txt + CHANGELOG.md changelog completed; stale vendor/wbcom-credits-sdk leftover removed from working tree before packaging; dist zip 2153 KB / 791 files."
      },
      {
        "date": "2026-05-24",
        "type": "diff-driven metadata refresh — no count changes",
        "summary": "Diff-driven refresh after 2026-05-21 → 2026-05-24 commit window (3 BC bug fixes + 1 template a11y + 1 RTL build script + 1 theme bridge). PHP source touched: includes/class-plugin.php (new dedupe_recurring_cron listener for BC 9910208588), includes/workflow/class-cron-scheduler.php (new dedupe_pending + dedupe_pending_batch static methods), includes/schema/class-schema-generator.php (new normalize_meta_for_schema defensive coercion for BC 9905075024), blocks/listing-detail/render.php (single-line: get_post_meta(_listora_is_verified) → wb_listora_is_verified() resolver for BC 9911539296). Templates: templates/blocks/user-dashboard/nav.php (role=tablist + aria-orientation=vertical). CSS: assets/css/listora-{components,variables}-rtl.css (auto-regen from new bin/build-css.mjs) + assets/css/themes/buddyx.css (legacy --color-* bridge tuning). Per category_sources globs: hooks_fired/cron sources touched but ground-truth grep confirms ZERO new fired hooks and ZERO new cron scheduling calls — all new functions are internal helpers (dedupe_pending, normalize_meta_for_schema) or listener registrations on existing core hooks (init priority 16). Coverage gate PASS: manifest 226 vs grep 210 unique-literal names (16-name delta is dynamic hooks like wb_listora_email_content_{$event}/wb_listora_feature_{$key}_enabled, wrapper-fired hooks, and multi-line apply_filters calls the single-line grep regex misses — same as documented previously). wppqa baseline 2026-05-24: 0 real findings, 8 false-positives. Also corrected stale summary.json counts (was 109+90=199, now matches manifest 120+106=226 — the 51d2e70 refresh on 2026-05-21 updated manifest.json but missed summary counts)."
      },
      {
        "date": "2026-05-18",
        "type": "diff-driven refresh after 5-commit fix wave + pre-launch additions",
        "summary": "Post 772316b (5 smoke fixes) + 773a89a (F-04/F-05) + 41c4a68 (5 BC bugs) + 5a4d0f9 (Edit-form-blank + Deactivate-View-404 HIGH IMPACT) + f4fb0b5 (Featured metabox + bulk-moderate REST + Anti-Spam helper + Free Contact Form). REST 53 → 55 (+/listings/bulk-moderate +/listings/{id}/contact-form). hooks_fired 192 → 198: +2 actions (wb_listora_after_bulk_moderate, wb_listora_after_contact_form_submit), +4 filters (wb_listora_login_modal_register_url for invite-only sites, wb_listora_render_contact_form for Pro lead_form coupling gate, wb_listora_contact_form_per_listing_daily_cap, wb_listora_contact_form_email_headers). 3 new classes (Anti_Spam, Contact_Form, Featured_Metabox). admin_pages unchanged. wppqa baseline 2026-05-18: 0 real findings, 1 nonce-no-cap FP (Featured metabox cap-before-nonce order — sniff scans wrong direction), 5 wiring FP (all service-layer reads, none should reach templates). Plus inline edits: D1 closed (REST envelope on /listings OFFSET branch wraps in same envelope as CURSOR + /search per no-UX-gaps policy); /detail timestamps consistency follow-up; D4 closed (4 wp_ajax_* documented as intentional admin-only exceptions); 3 doc-bug runbook fixes shipped."
      },
      {
        "date": "2026-05-07",
        "type": "refresh",
        "summary": "Diff-driven refresh after T1/T4/F1/O3 + post-PM block additions. +1 admin page (Email Log), +4 fired hooks (after_reactivate_listing, after_reset_settings, reset_option_keys, review_status_changed), +2 cross-plugin consumers (Pro reset_option_keys + after_reset_settings). All other categories unchanged."
      },
      {
        "date": "2026-05-07",
        "type": "phase-1+2+3 focused refresh",
        "summary": "Phase 1+2+3 commits applied. P1-1 (6 cron jobs migrated to Action Scheduler via new Cron_Scheduler abstraction). P1-2 (N+1 prefetch added to REST listings). P1-3 (43 apiFetch sites wrapped in AbortController + 10s timeout via new src/utils/abortable-fetch.js). P1-4 (105 bare 1fr CSS grid tracks → minmax(0, 1fr) across 29 files). P1-5 (4 new block render hooks: wb_listora_before_listing_card, wb_listora_after_listing_card, wb_listora_search_before_form, wb_listora_search_after_form). P1-6 (listora-submit-lock.js gated to consumers). P2-3 (new Capabilities::can_*() helpers + 5 cap constants). P2-8 (5 read-only settings sites routed through wb_listora_get_setting helper). P2-10 (declare(strict_types=1) on Migrated_From_Tracker + Cron_Scheduler). Derived caches refreshed: grid-track-overflow-risks 16 → 0, rest-hang-risks 43 → 0. NOTE: targeted refresh only — full hooks_fired re-scan deferred."
      },
      {
        "date": "2026-05-11",
        "type": "metadata refresh — no full re-scan",
        "summary": "Foundation cleanup Pass 3.1 + 3.2: admin CSS breakpoint consolidation (1700→1440, 900/960→1024 across admin.css + admin/dashboard.css + admin/settings.css + RTL twins) + CLAUDE.md doc additions (admin tap-target wp-admin-context exception, frontend v2 architecture diagram). Diff against manifest-category source globs returned 0 files — no PHP/JS/template/block changes. Per /wp-plugin-onboard --refresh diff-driven contract, full re-scan skipped. Summary + manifest generated.at bumped; counts unchanged."
      },
      {
        "date": "2026-05-11-evening",
        "type": "Pass 3 remediation complete (F1/F2/F3/F4/F5/F6 + D-P1P6)",
        "summary": "Foundation cleanup Pass 3 remediation: F1/F2 extracted 1 inline IAPI fallback to assets/js/listing-detail-fallback.js (Free) + 5 inline scripts to 4 asset files (Pro). F3 migrated 935 hex literals to v2 tokens across Free+Pro admin AND frontend CSS (1,072 admin + 1,138 frontend). F4 added .listora-admin-header primitive + auto-injection via in_admin_header hook. F6 added .listora-settings-card primitive + --auto variant. 4 new render helpers in class-render-helpers.php (admin_header, settings_card_open, settings_card_close + existing). 14 new admin-context tokens (--listora-wp-admin-*, --listora-admin-bg-*). plan/100k-readiness/PERFORMANCE-BUDGETS.md published (P1 TTFB + P6 Lighthouse targets). 2 encoding bugs fixed as side effect. 22 commits pushed."
      },
      {
        "date": "2026-05-12",
        "type": "diff-driven refresh — Social Links surface area + REST gap fill + admin_pages fixes",
        "summary": "Diff-driven refresh post 2026-05-12 HC-1 social_links delivery + bug-fix sweep. REST: +3 endpoints (listings/{id}/reactivate, settings/notifications/log/export, settings/notifications/log/retention) — all existed in source since prior commits but were missing from manifest. rest.endpoints count 50 → 53. admin_pages: Health Check parent corrected to '' (hidden stub — redirects to Settings > Advanced); Setup Wizard note updated to document dynamic parent ('listora' when setup incomplete, '' when complete) and the PHP 8 null→'' fix. No new blocks, AJAX, tables, capabilities, or hooks_fired. Social Links surface area now documented in FEATURE_AUDIT.md §1.2 (Submission), §3.x (REST listing-detail payload), CLAUDE.md Recent Changes. Coverage gate: all categories ≤5% gap (REST source 52 non-vendor = manifest 53 including 3 previously-missing, admin_pages 13 actual = 13 manifest — PASS)."
      }
    ],
    "last_consumed_by_refresh_from": "wb-listora-pro/wp-plugin-onboard refresh 2026-05-07",
    "last_consumed_by_refresh_at": "2026-05-07T07:24:27Z",
    "refresh_reason": "Phase 0 wppqa baseline + canonical primitives + INV-3 fix + page-registry helper + bug fixes (5 cards Ready for Testing)",
    "previous_at": "2026-06-06T17:30:00Z",
    "refresh_diff_files": 94
  },
  "interactivity": [
    {
      "block": "__shared_store__",
      "namespace": "listora/directory",
      "view_script": "src/interactivity/store.js",
      "actions": [
        {
          "name": "search",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": true,
          "has_timeout_ms": null
        },
        {
          "name": "searchImmediate",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "buildSearchURL",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setSearchQuery",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setLocation",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setFilter",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setFilterCheckbox",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleFeatureFilter",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setFilterSelect",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setFilterToggle",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setDateFilter",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setDateFrom",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setDateTo",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "clearFilter",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "clearAllFilters",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "selectType",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/listing-types/${ slug }/fields"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setSort",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setPage",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "nextPage",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "prevPage",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "setViewMode",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "nearMe",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "highlightMarker",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "unhighlightMarker",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "highlightCard",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "unhighlightCard",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "updateMapBounds",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showSuggestions",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "hideSuggestions",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "clearSearchQuery",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "fetchSuggestions",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/search/suggest?keyword=${ encodeURIComponent( state.searchQuery ) }&type=${ state.selectedType }"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "handleSuggestionKeydown",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleFavorite",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/favorites/${ listingId }",
            "/listora/v1/favorites"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "featureListing",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/listings/${ listingId }/feature"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "deactivateListing",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/listings/${ listingId }/deactivate"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "saveProfile",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/dashboard/profile"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "shareDialog",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showClaimModal",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showLoginModal",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "closeModal",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "submitClaim",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/claims"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleFiltersPanel",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "scrollFeaturedNext",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "scrollFeaturedPrev",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "navigateMonth",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showEventPopover",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "scrollFeaturedToPage",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "switchTab",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "switchGalleryImage",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleDetailReviewForm",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "submitDetailReviewForm",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/listings/${ ctx.listingId }/reviews"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "submitLeadForm",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [
            "/listora/v1/listings/${ ctx.listingId }/contact"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "syncURLParams",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "searchMapArea",
          "source": "src/blocks/listing-map/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "sortReviews",
          "source": "src/blocks/listing-reviews/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleReviewForm",
          "source": "src/blocks/listing-reviews/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "submitReviewForm",
          "source": "src/blocks/listing-reviews/view.js",
          "apiFetch_paths": [
            "/listora/v1/listings/${ ctx.listingId }/reviews"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "voteReviewHelpful",
          "source": "src/blocks/listing-reviews/view.js",
          "apiFetch_paths": [
            "/listora/v1/reviews/${ ctx.reviewId }/helpful"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showReportModal",
          "source": "src/blocks/listing-reviews/view.js",
          "apiFetch_paths": [
            "/listora/v1/reviews/${ ctx.reviewId }/report"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showReplyForm",
          "source": "src/blocks/listing-reviews/view.js",
          "apiFetch_paths": [
            "/listora/v1/reviews/${ ctx.reviewId }/reply"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "loadMoreReviews",
          "source": "src/blocks/listing-reviews/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleFiltersPanel",
          "source": "src/blocks/listing-search/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "selectTypeFromDropdown",
          "source": "src/blocks/listing-search/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "nextSubmissionStep",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "prevSubmissionStep",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "selectSubmissionType",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [
            "/listora/v1/listing-types/${ slug }/categories"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "handleSubmission",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [
            "/listora/v1/submit"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "saveDraft",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [
            "/listora/v1/submit"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "autoSaveDraft",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [
            "/listora/v1/submit"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "evaluateConditionalFields",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "validateField",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "openMediaUpload",
          "source": "src/blocks/listing-submission/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "switchDashTab",
          "source": "src/blocks/user-dashboard/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleListingMenu",
          "source": "src/blocks/user-dashboard/view.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "closeDashServices",
          "source": "src/interactivity/store.js",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        }
      ],
      "state_keys": [
        "searchQuery",
        "selectedType",
        "selectedLocation",
        "selectedCategory",
        "filters",
        "sortBy",
        "currentPage",
        "userLat",
        "userLng",
        "searchRadius",
        "mapBounds",
        "results",
        "facets",
        "isLoading",
        "hasSearched",
        "searchError",
        "typeFilters",
        "typeFieldConfig",
        "viewMode",
        "mapReady",
        "activeMarker",
        "highlightedCard",
        "markers",
        "showFiltersPanel",
        "showSuggestions",
        "suggestions",
        "recentSearches",
        "dateFilter",
        "dateFrom",
        "dateTo",
        "showEventPopover",
        "eventPopoverTitle",
        "eventPopoverDate",
        "eventPopoverUrl",
        "activeModal",
        "isClaimModalOpen",
        "isShareModalOpen",
        "isLoginModalOpen"
      ]
    },
    {
      "block": "listora/listing-grid",
      "view_script": "src/blocks/listing-grid/view.js",
      "actions": [],
      "state_keys": []
    },
    {
      "block": "listora/listing-map",
      "view_script": "src/blocks/listing-map/view.js",
      "actions": [
        {
          "name": "searchMapArea",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        }
      ],
      "state_keys": []
    },
    {
      "block": "listora/listing-reviews",
      "view_script": "src/blocks/listing-reviews/view.js",
      "actions": [
        {
          "name": "sortReviews",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleReviewForm",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "submitReviewForm",
          "apiFetch_paths": [
            "/listora/v1/listings/${ ctx.listingId }/reviews"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "voteReviewHelpful",
          "apiFetch_paths": [
            "/listora/v1/reviews/${ ctx.reviewId }/helpful"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showReportModal",
          "apiFetch_paths": [
            "/listora/v1/reviews/${ ctx.reviewId }/report"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "showReplyForm",
          "apiFetch_paths": [
            "/listora/v1/reviews/${ ctx.reviewId }/reply"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "loadMoreReviews",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        }
      ],
      "state_keys": []
    },
    {
      "block": "listora/listing-search",
      "view_script": "src/blocks/listing-search/view.js",
      "actions": [
        {
          "name": "toggleFiltersPanel",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "selectTypeFromDropdown",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        }
      ],
      "state_keys": []
    },
    {
      "block": "listora/listing-submission",
      "view_script": "src/blocks/listing-submission/view.js",
      "actions": [
        {
          "name": "nextSubmissionStep",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "prevSubmissionStep",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "selectSubmissionType",
          "apiFetch_paths": [
            "/listora/v1/listing-types/${ slug }/categories"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "handleSubmission",
          "apiFetch_paths": [
            "/listora/v1/submit"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "saveDraft",
          "apiFetch_paths": [
            "/listora/v1/submit"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "autoSaveDraft",
          "apiFetch_paths": [
            "/listora/v1/submit"
          ],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "evaluateConditionalFields",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "validateField",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "openMediaUpload",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        }
      ],
      "state_keys": []
    },
    {
      "block": "listora/user-dashboard",
      "view_script": "src/blocks/user-dashboard/view.js",
      "actions": [
        {
          "name": "switchDashTab",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        },
        {
          "name": "toggleListingMenu",
          "apiFetch_paths": [],
          "uses_abort_signal": false,
          "has_timeout_ms": null
        }
      ],
      "state_keys": []
    }
  ],
  "ui_activation": [
    {
      "selector": ".listora-detail__modal",
      "default_hidden_by": "blocks/listing-detail/style.css:939",
      "active_modifier": "is-open",
      "php_fallback": false,
      "files_searched": 219
    },
    {
      "selector": ".listora-migration-progress",
      "default_hidden_by": "assets/css/admin/migration.css:157",
      "active_modifier": "is-active",
      "php_fallback": false,
      "files_searched": 219
    },
    {
      "selector": ".listora-settings-section",
      "default_hidden_by": "assets/css/admin/settings.css:156",
      "active_modifier": "is-active",
      "php_fallback": true,
      "files_searched": 219
    }
  ],
  "static_analysis": {
    "dead_listeners": [],
    "cap_context_mismatches": [],
    "extensibility_gaps": [],
    "js_only_activation": [
      {
        "selector": ".listora-detail__modal",
        "default_hidden_by": "blocks/listing-detail/style.css:939",
        "active_modifier": "is-open",
        "php_fallback": false,
        "files_searched": 219
      },
      {
        "selector": ".listora-migration-progress",
        "default_hidden_by": "assets/css/admin/migration.css:157",
        "active_modifier": "is-active",
        "php_fallback": false,
        "files_searched": 219
      },
      {
        "selector": ".listora-settings-section",
        "default_hidden_by": "assets/css/admin/settings.css:156",
        "active_modifier": "is-active",
        "php_fallback": true,
        "files_searched": 219
      }
    ],
    "rest_hang_risks": [],
    "visual_required_no_enforcement": [
      {
        "template": "templates/blocks/listing-submission/step-media.php:27",
        "field_name": "featured_image",
        "missing_signals": [
          "aria-required"
        ],
        "hidden_input_at": "templates/blocks/listing-submission/step-media.php:52"
      }
    ],
    "grid_track_overflow_risks": [],
    "hook_signature_drift": []
  },
  "notes": [
    "Refreshed to v2.1 schema 2026-04-30. Phase 2.5.1-2.5.9 detectors all ran; static_analysis populated.",
    "Refresh 2026-04-30T16:30:00Z: added 3 derived modal-getter state keys (isClaimModalOpen, isShareModalOpen, isLoginModalOpen) to listora/directory namespace per commit 63411c8. Bumped schema_version to v2.1 to reflect manifest.summary.json + audit/derived/ cache + category_sources additions.",
    "T4 (2026-04-30): wppqa nonce-no-cap flag at includes/admin/class-pro-promotion.php:1188 (ajax_dismiss_promo) is a verified false positive. Action is registered as wp_ajax_wb_listora_dismiss_promo only — no _nopriv_ companion — so WP core gates to logged-in users upstream. Handler sets a per-user 3-day cookie (no DB write, no shared mutation). Adding current_user_can would over-restrict (CTA targets all logged-in users). No code change planned.",
    "T1 PM (2026-04-30T17:30:00Z): wppqa Rule 10 flag at src/interactivity/store.js:835 is a verified false positive. Commit f69f47f replaced the bare window.confirm() with the listoraConfirm modal at lines 827-833. The window.confirm() at line 835 is the right branch of a `window.listoraConfirm ? listoraConfirm(...) : window.confirm(...)` ternary — defensive fallback for CSP/ad-blocker scenarios where listora-confirm.js is unavailable. Symmetric to the documented Pro dashboard-needs.js:39 fallback. No code change planned.",
    "F10 import-canonicalization (1.2.0 wave-4): \\WBListora\\ImportExport\\Background_Import (includes/import-export/class-background-import.php) is the CANONICAL import engine. Every bulk import path routes through it: demo packs via queue_demo() (Setup Wizard class-setup-wizard.php:794, Settings class-settings-page.php:2803), file imports via queue_file() and the self-registered POST /import/queue/csv route (rest_queue_csv), progress via GET /import/progress/{run_id} (rest_progress). Public extension surface: wb_listora_queue_demo_import() / wb_listora_queue_file_import() / wb_listora_get_import_progress() in import-helpers.php (init() called there, line 35). The engine only orchestrates resumable, idempotent batching over Action Scheduler (hooks wb_listora_bg_import_batch + wb_listora_bg_import_finalize, group wb-listora) with a synchronous fallback (SYNC_THRESHOLD=10 / no AS); it REUSES the synchronous CSV_Importer / JSON_Importer / Demo_Seeder listing-creation, term-resolution, and 1.1.0 image dedupe/timeout code paths rather than re-implementing them. Per-run state lives in one autoload-off option wb_listora_bg_import_{run_id}. Async toggle is filterable via wb_listora_bg_import_use_async.",
    "1.2.0 refresh (2026-06-10): new classes this wave — \\WBListora\\ImportExport\\Background_Import + Hivepress_Migrator (canonical import engine + HivePress source migrator), \\WBListora\\REST\\Unsubscribe_Controller (signed-token opt-out), \\WBListora\\Privacy\\Privacy_Exporter/Privacy_Eraser (wp_privacy_personal_data_{exporters,erasers} registration in class-plugin.php), \\WBListora\\Features\\Analytics_Lite (Free view counting with wb_listora_pro_owns_analytics supersession), \\WBListora\\Bot_Detection (shared UA bot helper), Email_Templates_Page + Listing_Bulk_Actions (admin). New template: templates/blocks/user-dashboard/tab-favorites.php (+ before/after extension hooks). Coverage gate 2026-06-10: multiline-aware own-source scan = 130 unique do_action + 126 unique apply_filters literals; manifest 133 actions (130 + AS-fired wb_listora_bg_import_batch/finalize + libs-fired wbcom_credits_sdk_registry) / 126 filters — exact match, 0 gap. REST: 59 register_rest_route call sites -> 58 logical routes (GET /settings + PUT,DELETE /settings registered in 2 calls, merged per manifest convention). Unsubscribe route is GET-only (audit claim of GET/POST verified wrong). Stale consumed_by cleared on after_contact_form_submit/after_dashboard_reviews/after_map; Pro consumers added to 7 existing hooks (see cross-plugin-coupling.json — true Free-fires/Pro-consumes pair count is 69, correcting the prior under-counted 32)."
  ],
  "category_sources": {
    "rest": [
      "includes/rest/**/*.php"
    ],
    "ajax": [
      "includes/admin/**/*.php",
      "includes/**/*.php"
    ],
    "admin_pages": [
      "includes/admin/**/*.php"
    ],
    "settings": [
      "includes/admin/**/*.php"
    ],
    "shortcodes": [
      "includes/**/*.php"
    ],
    "blocks": [
      "blocks/**/*",
      "src/blocks/**/*"
    ],
    "post_types": [
      "includes/core/class-post-types.php"
    ],
    "taxonomies": [
      "includes/core/class-taxonomies.php"
    ],
    "tables": [
      "includes/class-activator.php",
      "includes/db/**/*.php"
    ],
    "capabilities": [
      "includes/core/class-capabilities.php"
    ],
    "services": [
      "includes/**/class-services*.php",
      "includes/**/services/**/*.php"
    ],
    "hooks_fired": [
      "includes/**/*.php",
      "blocks/**/*.php",
      "templates/**/*.php"
    ],
    "interactivity": [
      "src/interactivity/**/*.js",
      "src/blocks/**/view.js",
      "blocks/**/view.js"
    ],
    "ui_activation": [
      "assets/css/**/*.css",
      "blocks/**/*.css",
      "src/**/*.css",
      "templates/**/*.php"
    ],
    "frontend_assets": [
      "assets/**/*",
      "build/**/*"
    ],
    "cron": [
      "includes/**/class-cron*.php",
      "includes/**/*cron*.php"
    ],
    "wp_cli": [
      "includes/cli/**/*.php",
      "includes/**/class-cli*.php"
    ],
    "security": [
      "includes/security/**/*.php",
      "includes/**/class-nonce*.php"
    ],
    "static_analysis.dead_listeners": [
      "includes/**/*.php"
    ],
    "static_analysis.cap_context_mismatches": [
      "includes/**/*.php"
    ],
    "static_analysis.extensibility_gaps": [
      "includes/**/*.php",
      "templates/**/*.php"
    ],
    "static_analysis.js_only_activation": [
      "assets/css/**/*.css",
      "blocks/**/*.css",
      "src/**/*.css",
      "templates/**/*.php"
    ],
    "static_analysis.rest_hang_risks": [
      "src/**/*.js",
      "assets/**/*.js"
    ],
    "static_analysis.visual_required_no_enforcement": [
      "templates/**/*.php"
    ],
    "static_analysis.grid_track_overflow_risks": [
      "assets/css/**/*.css",
      "blocks/**/*.css",
      "src/**/*.css"
    ],
    "static_analysis.hook_signature_drift": [
      "includes/**/*.php"
    ]
  },
  "generated_at": "2026-06-10T00:00:00Z",
  "hooks_fired_count": 260
}
