Skip to main content

suma-dealer-locator

Help customers find authorized TenPoint crossbow dealers by location and distance.

Overview

Version: 3.0.2
Purpose: Provide dealer search functionality with location-based filtering
Namespace: Suma\DealerLocator
Dependencies: Carbon Fields (bundled), WP REST API
Framework: Suma Framework with version checking

Features

  • Location-based search: Find dealers within specified radius
  • Distance calculation: Accurate distance computation using coordinates
  • REST API integration: Public API endpoint for dealer queries
  • Custom fields management: Carbon Fields for dealer data entry
  • Visual Composer support: Legacy page builder integration
  • Admin interface: Dedicated admin page for dealer management
  • i18n ready: Internationalization support

File Structure

suma-dealer-locator/
├── suma-dealer-locator.php # Entry point with version checker
├── includes/
│ ├── class-suma-dealer-locator.php # Main plugin class (extends Base)
│ ├── class-activator.php # Plugin activation logic
│ ├── class-deactivator.php # Plugin deactivation logic
│ ├── class-i18n.php # Internationalization
│ ├── class-utils.php # Utility functions
│ ├── class-custom-routes.php # REST API endpoints
│ └── class-visual-composer.php # Visual Composer integration
├── admin/
│ └── class-admin.php # Admin functionality
├── frontend/
│ └── class-frontend.php # Frontend display
├── framework/
│ └── includes/
│ └── class-version.php # Version checking
├── vendor/
│ └── carbon-fields/ # Custom fields library
└── languages/ # Translation files

Main Classes

Suma_Dealer_Locator

Main plugin orchestrator that manages the plugin lifecycle.

namespace Suma\DealerLocator;

class Suma_Dealer_Locator extends Base {
// Manages activation, deactivation, and component loading
}

Activator

Handles plugin activation tasks.

public static function activate() {
// Create dealer custom post type
// Flush rewrite rules
// Set default options
}

Deactivator

Handles plugin deactivation tasks.

public static function deactivate() {
// Clean up transients
// Flush rewrite rules
// Preserve user data (never delete on deactivation)
}

REST API

Base URL

/wp-json/suma-dl/v2/

Authentication

Public endpoint (no authentication required)

Endpoint: Get Dealers

Method: POST
Route: /suma-dl/v2/get_dealers
Purpose: Find dealers within a specified radius of a location

Request Body (JSON)

{
"latitude": 39.9612,
"longitude": -82.9988,
"radius": 50,
"unit": "miles"
}

Request Parameters

ParameterTypeRequiredDescription
latitudefloatYesLatitude of search center point
longitudefloatYesLongitude of search center point
radiusintNoSearch radius (default: 25)
unitstringNo'miles' or 'km' (default: 'miles')

Response (JSON)

{
"success": true,
"dealers": [
{
"id": 123,
"name": "Crossbow Pro Shop",
"address": "123 Main St",
"city": "Columbus",
"state": "OH",
"zip": "43215",
"phone": "(614) 555-1234",
"website": "https://example.com",
"latitude": 39.9612,
"longitude": -82.9988,
"distance": 2.4,
"distance_unit": "miles"
}
],
"count": 1,
"max_results": 200
}

Response Limits

  • Maximum results: 200 dealers
  • Results ordered by distance (nearest first)
  • Includes calculated distance for each dealer

Error Responses

Missing coordinates:

{
"success": false,
"error": "Latitude and longitude are required"
}

Invalid coordinates:

{
"success": false,
"error": "Invalid latitude or longitude values"
}

Custom Fields (Carbon Fields)

Dealer custom post type uses Carbon Fields for data entry.

Dealer Fields

Field NameTypeDescription
dealer_addresstextStreet address
dealer_address_2textAddress line 2
dealer_citytextCity
dealer_statetextState/Province
dealer_ziptextPostal code
dealer_countrytextCountry
dealer_phonetextPhone number
dealer_emailtextEmail address
dealer_websitetextWebsite URL
dealer_latitudetextLatitude (auto-calculated)
dealer_longitudetextLongitude (auto-calculated)
dealer_descriptiontextareaDealer description
dealer_logoimageDealer logo

Auto-Geocoding

When a dealer address is saved, the plugin automatically:

  1. Geocodes the full address
  2. Stores latitude and longitude
  3. Validates coordinate accuracy

Distance Calculation

The plugin uses the Haversine formula for accurate distance calculations between coordinates.

Haversine Formula Implementation

function calculate_distance($lat1, $lon1, $lat2, $lon2, $unit = 'miles') {
$earth_radius = ($unit === 'km') ? 6371 : 3959; // km or miles

$lat_diff = deg2rad($lat2 - $lat1);
$lon_diff = deg2rad($lon2 - $lon1);

$a = sin($lat_diff / 2) * sin($lat_diff / 2) +
cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
sin($lon_diff / 2) * sin($lon_diff / 2);

$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$distance = $earth_radius * $c;

return round($distance, 2);
}

Admin Interface

Dealer Management

Located in: WP Admin → Dealers

  • List all dealers
  • Add new dealer
  • Edit dealer information
  • Delete dealers
  • Bulk actions
  • Search dealers

Custom Columns

ColumnContent
TitleDealer name
LocationCity, State
PhonePhone number
Distance(shown in search results)

Frontend Integration

Theme Integration

The theme integrates the dealer locator via:

wp-content/themes/elementor/inc/class-dealer-locator.php

REST API Call Example

fetch('/wp-json/suma-dl/v2/get_dealers', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
latitude: 39.9612,
longitude: -82.9988,
radius: 50,
unit: 'miles'
})
})
.then(response => response.json())
.then(data => {
console.log('Found dealers:', data.dealers);
})
.catch(error => {
console.error('Error:', error);
});

JavaScript Integration

The theme provides a dealer search interface that:

  1. Gets user's current location (with permission)
  2. Or allows manual address/zip entry
  3. Geocodes the search location
  4. Calls the REST API endpoint
  5. Displays results on a map
  6. Lists dealers with distance

Visual Composer Integration

Legacy support for Visual Composer page builder.

Shortcode

[suma_dealer_locator]

Parameters

ParameterDefaultDescription
radius25Default search radius
unitmilesDistance unit
map_height400Map height in pixels

Internationalization

Text Domain

suma-dealer-locator

Translation Files

Located in: languages/

Translatable Strings

All user-facing text is wrapped in translation functions:

__('Find a Dealer', 'suma-dealer-locator');
_e('Search Results', 'suma-dealer-locator');
_n('%s dealer found', '%s dealers found', $count, 'suma-dealer-locator');

Database Storage

Custom Post Type

Name: dealers
Supports: title, editor, thumbnail
Hierarchical: No
Public: Yes (front-end viewable)
Show in REST: Yes

Meta Keys

Meta KeyStorageDescription
_dealer_addressPost metaStreet address
_dealer_cityPost metaCity
_dealer_statePost metaState
_dealer_zipPost metaPostal code
_dealer_latitudePost metaLatitude coordinate
_dealer_longitudePost metaLongitude coordinate
_dealer_phonePost metaPhone number
_dealer_emailPost metaEmail address
_dealer_websitePost metaWebsite URL

Geocoding Service

The plugin uses a geocoding service to convert addresses to coordinates.

Service Options

  • Google Maps Geocoding API (if API key configured)
  • OpenStreetMap Nominatim (fallback, free)

Geocoding Process

  1. User enters/updates dealer address
  2. Plugin sends address to geocoding service
  3. Service returns latitude/longitude
  4. Coordinates saved to post meta
  5. Coordinates used for distance calculations

Performance Optimization

Caching

  • Dealer coordinates cached in post meta
  • Geocoding results cached to avoid API rate limits
  • Database queries use indexed meta queries

Query Optimization

  • Uses meta queries with coordinate boundaries
  • Limits results to 200 dealers
  • Calculates distance only for dealers within rough boundary

Transients

Dealer search results can be cached with transients:

$cache_key = 'dealers_' . md5($lat . $lon . $radius);
$results = get_transient($cache_key);

if (false === $results) {
$results = perform_dealer_search();
set_transient($cache_key, $results, HOUR_IN_SECONDS);
}

Security

Input Validation

  • Latitude/longitude validated as floats
  • Radius validated as positive integer
  • Unit validated against allowed values

Sanitization

$latitude = floatval($_POST['latitude']);
$longitude = floatval($_POST['longitude']);
$radius = absint($_POST['radius']);
$unit = in_array($_POST['unit'], ['miles', 'km']) ? $_POST['unit'] : 'miles';

Output Escaping

All dealer data escaped before output:

echo esc_html($dealer['name']);
echo esc_url($dealer['website']);
echo esc_attr($dealer['phone']);

Troubleshooting

No Dealers Found

  • Verify dealer addresses have valid coordinates
  • Check radius is appropriate for dealer density
  • Confirm geocoding service is working
  • Review PHP error logs

Incorrect Distances

  • Verify latitude/longitude accuracy
  • Check unit parameter (miles vs km)
  • Ensure Haversine formula implementation correct

REST API Errors

  • Check permalink structure (Settings → Permalinks → Save)
  • Verify REST API enabled
  • Check for conflicting plugins
  • Review server error logs

Version History

v3.0.2 (Current)

  • Enhanced REST API with v2 namespace
  • Improved distance calculation accuracy
  • Carbon Fields integration
  • Performance optimizations

v2.x

  • Visual Composer integration
  • Admin interface improvements

v1.0

  • Initial release