Import listings from Google Maps scraper JSON exports via Listings > Import.
Local Directory can bulk-import listings from Google Maps scraper JSON exports. JSON (JavaScript Object Notation) is a standard text format for storing structured data — it is the format you get when exporting saved places from Google Maps, and the plugin can read and import it automatically. Navigate to Listings > Import in your WordPress admin to open the import wizard. The importer handles field mapping, photo downloads, duplicate detection via PlaceID, AI-generated descriptions, and automatic location taxonomy creation.
The importer expects a JSON array of objects. Each object represents one listing. The following fields are recognized and mapped automatically:
| Field | Type | Maps to |
|---|---|---|
name |
string | Post title |
address |
string | Location + auto-detected taxonomy terms |
lat |
float | Latitude coordinate |
lng |
float | Longitude coordinate |
phone |
string | _ld_phone |
website |
string | _ld_website |
rating |
float | ld_ratings_summary |
reviewsCount |
int | total_ratings |
primaryCategory |
string | _ld_primary_category |
openingHours |
object | _ld_opening_hours |
openingHoursText |
string | _ld_opening_hours_text |
photoUrls |
array | Media library (max 10 photos) |
aboutData |
object | _ld_about_data |
businessStatus |
string | _ld_business_status (OPERATIONAL, CLOSED_TEMPORARILY, CLOSED_PERMANENTLY) |
googleMapsUrl |
string | google_maps_url in locations data |
placeId |
string | google_place_id (used for duplicate detection) |
plusCode |
string | _ld_plus_code |
scrapedAt |
string | Import log timestamp |
id |
string | Reference ID (stored for traceability) |
Unrecognized fields: Any fields in the JSON that are not listed above are still imported. They are stored as post meta with a _ld_gm_ prefix so no data is lost.
A valid import file only needs the name field. In practice, most scraper exports include at least these fields:
[
{
"name": "Mario's Pizzeria",
"address": "Via Roma 15, 00184, Rome, Italy",
"lat": 41.8967,
"lng": 12.4822,
"phone": "+39 06 1234567",
"primaryCategory": "Pizza Restaurant",
"rating": 4.5,
"reviewsCount": 128
}
]
The import wizard walks you through four steps. Navigate to Listings > Import to begin.
Drag-and-drop your JSON file onto the upload area, or click to browse. Once the file is parsed, the wizard displays a summary:
Set your import preferences before processing begins:
| Option | Values | Description |
|---|---|---|
| Duplicates | Skip / Update |
What to do when a listing with the same PlaceID already exists. |
| Post Status | Publish / Pending |
Whether imported listings go live immediately or wait for review. |
| Download Photos | On / Off |
Download photos from photoUrls into the WordPress media library. |
| Category | Dropdown | Assign all imported listings to a specific category, or let primaryCategory create/match terms automatically. |
| Location | Auto-detect / Dropdown |
Parse the address to detect city and country, or assign a fixed location taxonomy term. |
| AI Descriptions | On / Off |
Generate descriptions, SEO titles, and meta via OpenRouter. Requires an OpenRouter API key in settings. |
The importer processes listings in batches of 10 (configurable via the ld_import_batch_size filter). A progress bar shows how many batches have completed. You can safely navigate away from the page and return later — processing continues in the background via WP-Cron (WordPress's built-in task scheduler that handles background jobs like processing imports, sending emails, and checking listing expiry dates) and will resume where it left off.
Performance tip: If you are importing thousands of listings with photos and AI descriptions, consider running WP-Cron via a real cron job (define('DISABLE_WP_CRON', true);) for more reliable background processing.
When processing completes, the summary screen shows final counts:
When photo downloading is enabled, the importer avoids re-downloading images that already exist in the media library. Here is how the deduplication mechanism works:
_ld_source_url meta value stored on the WordPress attachment post. This records the original remote URL the image was fetched from.
_ld_source_url.
photoUrls array. The first photo becomes the featured image.
When enabled, the importer sends listing data (name, category, address, about data) to an AI model via OpenRouter to generate rich content automatically.
Before using AI descriptions, configure the following in Listings > Settings > Import:
OpenRouter API Key — paste your key from openrouter.ai/keys.
Model — select the AI model to use (e.g., google/gemini-2.0-flash-001).
Language — the language for generated content (defaults to your site language).
Word count — target length for the generated description.
Prompt — customize the system prompt sent to the AI. The default prompt instructs the model to write an informative, SEO-friendly description.
For each listing, the AI generates up to four pieces of content:
| Generated Content | Stored In | Notes |
|---|---|---|
| Description | post_content |
The main listing description, written in the configured language and word count. |
| SEO Title | Yoast / Rank Math title | Optimized page title. Falls back to _ld_seo_title meta if no SEO plugin is active. |
| Meta Description | Yoast / Rank Math meta desc | 150-160 character summary for search engine results. |
| Focus Keyphrase | Yoast / Rank Math keyphrase | Primary keyword phrase for on-page SEO scoring. |
Cost: AI generation uses your OpenRouter credits. A typical listing costs less than $0.001 with a fast model like Gemini Flash. A 1,000-listing import typically costs under $1.00.
When the Location option is set to Auto-detect, the importer parses the address field to extract city and country taxonomy terms. Here is how it works:
The address string is split by commas into segments.
The last segment is treated as the country.
The second-to-last segment is treated as the city.
If the taxonomy terms do not already exist, they are created automatically. The city term is nested under the country term.
Given the address:
"Via Roma 15, 00184, Rome, Italy"
The parser extracts:
| Segment | Detected As | Taxonomy Term |
|---|---|---|
Italy |
Country (last) | Created as top-level location term |
Rome |
City (second-to-last) | Created as child of Italy |
Tip: If auto-detection does not produce the right results for your data, select a specific location from the dropdown in Step 2 instead. You can always reassign locations after import via the bulk editor.
Developers can customize the import process using the following WordPress hooks:
| Hook | Type | Description |
|---|---|---|
ld_import_field_mapping |
Filter | Modify the field mapping array before a record is processed. Receives the mapping array and the raw JSON record. Use this to rename fields, add custom mappings, or remove fields from import. |
ld_import_filter_about_data |
Filter | Filter the aboutData object before it is stored. Useful for cleaning, restructuring, or extracting specific values from the about data. |
ld_after_import_listing |
Action | Fires after a single listing has been fully imported. Receives $post_id (the new listing post ID) and $record (the original JSON object). Use this to add custom post meta, trigger notifications, or sync with external systems. |
add_filter( 'ld_import_field_mapping', function( $mapping, $record ) {
// Map a custom JSON field to post meta
if ( isset( $record['myCustomField'] ) ) {
$mapping['_ld_custom_value'] = $record['myCustomField'];
}
return $mapping;
}, 10, 2 );
add_action( 'ld_after_import_listing', function( $post_id, $record ) {
// Log the import to a custom table
global $wpdb;
$wpdb->insert( $wpdb->prefix . 'import_log', [
'post_id' => $post_id,
'place_id' => $record['placeId'] ?? '',
'imported' => current_time( 'mysql' ),
] );
}, 10, 2 );