Map Integration
A secure WordPress plugin for integrating maps into your site with comprehensive geocoding capabilities.
by Danny Dollars · github.com/dmathesonpathfinder/map-integration · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/dmathesonpathfinder/map-integration/archive/refs/heads/main.zipA WordPress plugin that renders interactive maps and a searchable member directory with automated geocoding. Coordinates are resolved from MemberPress profile address fields using Google Maps (primary) or OpenStreetMap Nominatim (fallback) and cached in the database.
Requirements
- WordPress 5.0+
- MemberPress (member address data sourced from
mepr_*user meta) - Google Maps API key (optional — enables higher-accuracy geocoding)
Installation
- Upload the
map-integrationfolder to/wp-content/plugins/ - Activate Map Integration in Plugins → Installed Plugins
- Go to Settings → Map Integration to configure your Google Maps API key
Shortcodes
[map_integration]
Embeds an interactive Leaflet map showing member locations.
[chiropractor_directory]
Displays a searchable member directory with map pins.
| Attribute | Default | Description |
|---|---|---|
show_search |
true |
Show or hide the search bar ("false" to hide) |
[chiropractor_directory]
[chiropractor_directory show_search="false"]
Admin Tools
Settings → Map Integration
- Enter and save a Google Maps API key
- Run a test geocode against any address
- Parse a street address into its components
- View geocoding cache statistics
- Clear all cached geocoding results, or only entries older than N days
Geocoding
Addresses are geocoded from MemberPress user meta fields (street, city, province). The resolved coordinates are stored back as user meta and reused on subsequent page loads.
Provider Order
- Google Maps Geocoding API — used when an API key is configured; returns a confidence score based on
location_type(ROOFTOP → 100, RANGE_INTERPOLATED → 90, GEOMETRIC_CENTER → 70, APPROXIMATE → 50) - Nominatim (OpenStreetMap) — free fallback; confidence scored by result class/type (house/building → 95, highway/place → 80, other → 60–70)
Address Variations
When geocoding fails on the first attempt, the plugin retries with progressively simplified address strings:
{street}, {city}, {province}, Canada{street}, {city}, {province}- Street cleaned of suite/unit/PO Box/floor references, then the same two forms
Rate Limiting
- Nominatim: 1 request per second
- Google: 0.1 second minimum between requests
Cache
Results are stored in a custom geocoded_addresses database table (created on activation). Cache TTL defaults to 30 days. Entries can be cleared from the admin tools page.
Coordinate Storage (User Meta)
Geocoded results are written to the following user meta keys (suffix '' for primary location, _2 etc. for additional locations):
| Key | Description |
|---|---|
mepr_clinic_lat |
Latitude |
mepr_clinic_lng |
Longitude |
mepr_clinic_geocoded_at |
Timestamp of last geocode |
mepr_clinic_geo_confidence |
Confidence score (0–100) |
mepr_clinic_geo_provider |
google or nominatim |
mepr_clinic_geo_fallback |
Whether a fallback strategy was used |
Coordinates with a confidence score ≥ 80 or sourced from Google are not re-geocoded on subsequent requests.
PHP API
Three functions are available for use in themes or other plugins:
// Geocode an address string, returns array with lat/lng or false
$result = geocode_address('123 Main St, Halifax, Nova Scotia', [
'providers' => ['nominatim', 'google'],
'use_cache' => true,
'country_code' => 'ca',
]);
// $result['lat'], $result['lng'], $result['confidence_score'], $result['provider']
// Parse a raw street address into components
$parts = parse_street_address('123 Main St Suite 4, Halifax');
// Returns array of parsed components
// Clear the geocoding cache
$count = clear_geocoding_cache(); // clear all
$count = clear_geocoding_cache(['older_than' => 30 * 86400]); // older than 30 days
File Structure
├── map-integration.php # Main plugin file (MapGeocoder + MapIntegration classes)
├── includes/
│ ├── class-geocoding-service.php # Multi-provider geocoding service with cache
│ ├── class-street-parser.php # Street address parser and normaliser
│ └── geocoding-functions.php # Public helper functions (geocode_address, etc.)
├── admin/
│ └── partials/
│ └── geocoding-test.php # Admin test/cache management UI
└── assets/
├── chiropractor-directory.css
├── chiropractor-directory.js
├── leaflet.css # Leaflet map library styles
└── style.css
Security (v1.0.1)
- All database queries use prepared statements
- User input validated and sanitised before geocoding or storage
- API key masked in all log output
- External HTTP requests restricted to whitelisted hosts (Google Maps, Nominatim)
- SSL enforced for all outbound API calls
- Log files stored in the uploads directory behind
.htaccessdeny rules, with 5 MB size cap and 90-day automatic rotation - File logging disabled in production environments unless
MAP_INTEGRATION_ALLOW_FILE_LOGGINGis defined - Nonce verification on all admin form submissions
manage_optionscapability required for all admin operations
Configuration Constants
| Constant | Default | Description |
|---|---|---|
MAP_INTEGRATION_MAX_LOG_SIZE |
5242880 (5 MB) |
Maximum log file size |
MAP_INTEGRATION_MAX_CACHE_ENTRIES |
10000 |
Maximum geocoding cache entries |
MAP_INTEGRATION_RATE_LIMIT_WINDOW |
60 |
Rate limit window in seconds |
MAP_INTEGRATION_ALLOW_FILE_LOGGING |
(unset) | Define to enable file logging in production |
License
GPL-2.0+