Import Guide

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.

Expected JSON Format

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.

Minimal JSON Example

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
  }
]

Import Wizard

The import wizard walks you through four steps. Navigate to Listings > Import to begin.

Step 1 — Upload

Drag-and-drop your JSON file onto the upload area, or click to browse. Once the file is parsed, the wizard displays a summary:

  • Total records found in the file
  • New listings that will be created (no matching PlaceID found)
  • Existing listings already in the database (matched by PlaceID)

Step 2 — Configure

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.

Step 3 — Processing

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.

Step 4 — Summary

When processing completes, the summary screen shows final counts:

  • + Imported — new listings created
  • Updated — existing listings refreshed with new data
  • Skipped — duplicates that were not updated
  • AI AI successes / failures — how many listings got AI-generated content

Photo Deduplication

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:

  • Every downloaded photo gets a _ld_source_url meta value stored on the WordPress attachment post. This records the original remote URL the image was fetched from.
  • Before downloading a photo, the importer queries the media library for an existing attachment with a matching _ld_source_url.
  • If a match is found, the existing attachment ID is reused and no HTTP request is made. This saves bandwidth and storage.
  • This means you can safely re-import the same JSON file (e.g., with updated ratings or hours) without duplicating photos in your media library.
  • A maximum of 10 photos per listing are downloaded from the photoUrls array. The first photo becomes the featured image.

AI Description Generation

When enabled, the importer sends listing data (name, category, address, about data) to an AI model via OpenRouter to generate rich content automatically.

Setup

Before using AI descriptions, configure the following in Listings > Settings > Import:

  1. 1

    OpenRouter API Key — paste your key from openrouter.ai/keys.

  2. 2

    Model — select the AI model to use (e.g., google/gemini-2.0-flash-001).

  3. 3

    Language — the language for generated content (defaults to your site language).

  4. 4

    Word count — target length for the generated description.

  5. 5

    Prompt — customize the system prompt sent to the AI. The default prompt instructs the model to write an informative, SEO-friendly description.

What Gets Generated

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.

Location Auto-Detection

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:

  1. 1

    The address string is split by commas into segments.

  2. 2

    The last segment is treated as the country.

  3. 3

    The second-to-last segment is treated as the city.

  4. 4

    If the taxonomy terms do not already exist, they are created automatically. The city term is nested under the country term.

Example

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.

Hooks

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.

Example: Custom Field Mapping

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 );

Example: Post-Import Action

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 );