# Automotive Inventory Importer – Plugin Documentation

## Overview

**Automotive Inventory Importer** is a WordPress plugin (v2.2.5) that automatically syncs a car dealership's vehicle inventory from an XML feed into a WordPress website. No manual data entry is required.

- **Author:** Muhammad Jawaid Shamshad – Ibexoft
- **Requires PHP:** 8.0+
- **License:** GNU Public License

---

## v2 Feature Set

### What v2 Does Today

v2 is a fully automated XML-to-WordPress vehicle inventory sync plugin. Once configured, it runs on a schedule, pulls your XML feed, and keeps your vehicle listings (a custom post type called `vehicles`) in sync — adding new vehicles, updating existing ones, and downloading images into your Media Library. No manual data entry is needed after setup.

---

### Settings

The plugin's settings page lives at **WordPress Admin → Settings → Automotive Inventory Importer**. It has four tabs.

---

#### Tab 1 – Feed & Sync

Configure your inventory source and sync schedule.

![Feed & Sync settings tab](screenshot-1.png)

| Option | Description | Default |
|--------|-------------|---------|
| **Your Inventory Link** | Full URL or server path to your XML feed file. Click **Browse Server** to pick a local file on the server. | (empty) |
| **How Often to Sync** | How frequently WP Cron checks for updates. Options: Every 5 Minutes, Every 10 Minutes, Every 15 Minutes, Every 30 Minutes, Hourly, Twice Daily, Daily. | Every 10 Minutes |

**Action buttons on this tab:**

| Button | What it does |
|--------|-------------|
| **Save Changes** | Saves the feed URL and sync frequency. Reschedules the WP Cron event to the new interval (requires plugin deactivation/reactivation if changing frequency). |
| **Test Inventory Link** | Validates that the URL or file path is reachable and returns parseable XML. |
| **Sync Inventory Now** | Runs the full import immediately, regardless of schedule. Results appear in the Import History tab. |
| **Download Sample Feed** | Downloads a sample XML file you can use as a template for your own feed. |
| **Configure Field Mapping** | Shortcut that jumps directly to the Field Mapping tab. |

A **Quick Start Guide** sidebar on the right walks through setup in four steps.

---

#### Tab 2 – Field Mapping

Map the fields in your XML feed to the WordPress post meta keys the plugin stores.

![Field Mapping settings tab](screenshot-6.png)

When a valid feed URL is saved, the plugin parses a sample of the feed and auto-detects all field names present (e.g. "Found 31 fields in your feed"). Each detected field appears as a row with:

| Column | Description |
|--------|-------------|
| **Enable** | Checkbox to include or exclude this field from the import. Unchecked fields are ignored entirely. |
| **Feed Field (Source)** | The raw XML tag name from your feed (e.g. `manufacturer`, `stock_number`). |
| **Target Meta Field** | Dropdown to choose which WordPress post meta key this field is stored under. Includes all standard known fields plus a `(custom)` option that stores under the field's own name. |
| **Sample Value** | Shows an actual value from the feed so you know what you're mapping. |

This allows you to use any XML feed — even one with non-standard field names — by remapping source fields to the plugin's known meta keys.

---

#### Tab 3 – Page Templates

Control how vehicle post titles and descriptions are generated.

![Page Templates settings tab](screenshot-7.png)

| Option | Description | Default |
|--------|-------------|---------|
| **Vehicle Page Title Template** | Token-based pattern for the post title. Use any XML field name wrapped in `{}`. | `{manufacturer} {brand} {model_year}` |
| **Vehicle Description Template** | Token-based pattern for the post body content. Use any XML field name wrapped in `{}`. | `{designation}, {manufacturer}, {brand}, {model}, {model_year}` |

Example: `{manufacturer} {brand} {model_year}` → **Toyota Camry 2024**

---

#### Tab 4 – Import History

Live log of all past import runs.

![Import History tab](screenshot-3.png)

Each log entry is timestamped and shows:
- Import start/end events
- Number of vehicles found in the feed
- Number created, updated, and skipped
- Any errors (e.g. missing `stock_number`, failed image download)
- Individual vehicle creation/update lines

A **Clear History** button wipes the log file.

The log is also written to disk at `wp-content/uploads/automotive-feed-import/import-log.txt`.

---

### Vehicle Edit Screen

Each imported vehicle is a WordPress post of the custom `vehicles` post type. The edit screen shows a **"Vehicle Information (Imported from Feed)"** meta box with all imported fields editable:

![Vehicle edit screen meta box](screenshot-2.png)

Fields shown in the meta box include Stock Number, Body Type, Mileage, Designation, and all other fields from the feed. Values can be edited manually and will survive the next import (the import overwrites from feed data, so manual edits may be overwritten on the next sync).

---

### Frontend Display

The plugin hooks into `the_content` filter to render vehicle data automatically on vehicle post pages and archive listings — no theme modifications required.

**Archive / listing card view:**

![Vehicle listing card on the frontend](screenshot-4.jpeg)

Each card shows the featured image (or the bundled placeholder if no image is available), the vehicle title, price, Year/Color/Condition summary, and a **View Details** button.

**Single vehicle detail page:**

![Vehicle detail page on the frontend](screenshot-5.jpeg)

The full detail page shows:
- Featured image (or placeholder with "NO VEHICLE PHOTO AVAILABLE" label)
- Post description generated from the Page Template
- A **Vehicle Specifications** table listing: Stock Number, Manufacturer, Brand, Model, Year, Condition, Type, Color, Length, Price, Status

---

### Image Handling

- The plugin downloads all images from `image_urls`, `images`, `photos`, `image1`/`photo1`, etc. fields into the WordPress Media Library.
- The first image is set as the **featured image** of the vehicle post.
- If no images are present in the feed, the bundled `assets/car_placeholder.png` is used as the featured image.
- Images are only downloaded once per URL; re-importing the same vehicle does not re-download existing images.

---

### Custom Post Type: `vehicles`

| Property | Value |
|----------|-------|
| Slug | `vehicles` |
| Archive URL | `/vehicles/` |
| Menu position | 5 (below Posts) |
| Menu icon | `dashicons-car` |
| Supports | title, editor, thumbnail, custom-fields |

---

## How It Works

### Data Flow

```
XML Feed (URL or local file)
    → load_xml()        — parses XML into array of vehicle units
    → update_data()     — loops through units
        → Looks up stock_number in DB
        → add_listing()         — creates new vehicle post (if not found)
        → update_inventory()    — saves all fields as post meta
        → process_images()      — downloads and attaches images
```

### Core Features

| Feature | Details |
|---------|---------|
| XML Feed Source | Local file path or remote HTTP/HTTPS URL |
| Sync Schedule | Configurable: every 5, 10, 15, or 30 minutes (WP Cron) |
| Manual Import | Available from the Settings page |
| Custom Post Type | Registers `vehicles` CPT with car dashicon |
| Legacy Migration | One-time migration of old `listing` posts to `vehicles` |
| Field Mapping | Map XML source fields to target meta field names |
| Image Import | Downloads images into Media Library, sets featured image |
| Placeholder Image | Falls back to bundled `assets/car_placeholder.png` if no images |
| Theme Compatibility | Maps fields to Automotive Theme meta keys automatically |

---

## XML Feed Format

### Structure

The plugin uses a **simple, flat, vendor-agnostic XML** structure:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<RootElement>
  <UnitElement>
    <field_name>value</field_name>
    <another_field>value</another_field>
  </UnitElement>
</RootElement>
```

- The **root element name** does not matter (`<Inventory>`, `<Feed>`, `<Vehicles>`, etc.)
- The **unit element name** does not matter (`<Unit>`, `<Vehicle>`, `<Car>`, etc.)
- **Field tag names** become the WordPress post meta keys automatically

### Supported Fields

| Field | Description |
|-------|-------------|
| `stock_number` | **Required.** Unique identifier used for upsert logic |
| `vin` | Vehicle Identification Number |
| `manufacturer` | Make (e.g., Toyota, Ford) |
| `brand` | Brand/model line (e.g., Camry, F-150) |
| `model` | Trim/variant (e.g., XSE, Lariat) |
| `model_year` | Year |
| `designation` | Condition: NEW, USED, CERTIFIED PRE-OWNED |
| `designation_code` | Short code: N, U, C |
| `type` | Vehicle type: SEDAN, SUV, PICKUP TRUCK, etc. |
| `type_code` | Short code: SD, SUV, PU, etc. |
| `body_type` | Body style |
| `style` | Style descriptor |
| `status` | AVAILABLE, SOLD, etc. |
| `status_code` | Short code: A, S, etc. |
| `exterior_color` | Exterior color |
| `interior_color` | Interior color |
| `mileage` | Odometer reading |
| `special_web_price` | Web/sale price |
| `base_list` | Base list price |
| `factory_list` | Factory list price |
| `total_list` | Total list price |
| `take_price` | Take price |
| `show_web_price` | Display web price |
| `length` | Vehicle length |
| `width` | Width |
| `height` | Height |
| `weight` | Weight |
| `chassis_no` | Chassis number |
| `serial_no` | Serial number |
| `lot_location` | Lot location name |
| `lot_location_code` | Lot location code |
| `gl_location_code` | GL location code |
| `web_dealer_id` | Dealer ID |
| `received_date` | Date received |
| `sold_date` | Date sold |
| `description` | Vehicle description |
| `features` | Feature list (comma-separated) |
| `options` | Options |
| `notes` | Internal notes |
| `image_urls` | Comma/pipe/space-separated image URLs |
| `images` | Alternative image URL list field |
| `photos` | Alternative image URL list field |
| `image1`, `image2`, ... | Individual image URL fields |
| `photo1`, `photo2`, ... | Individual photo URL fields |

### Theme Compatibility Fields (auto-mapped)

The plugin automatically writes these additional meta keys for Automotive Theme compatibility:

| XML Field | Theme Meta Key |
|-----------|---------------|
| `manufacturer` | `manufacturer_level2_value` |
| `model_year` | `year_value` |
| `special_web_price` | `price_value` |
| `mileage` | `mileage_value` |
| `exterior_color` | `color_value` |

---

## Sample XML

A sample inventory file is included at `sample-inventory.xml` with 4 vehicle entries demonstrating all common fields including image URLs.

The original IDS DMS sample is at `Web_Inventory_999.xml` (RV/trailer inventory, no image URLs).

---

## Industry Standard Compatibility

### Does the XML format follow an industry standard?

**No.** The plugin uses a simplified, flat, vendor-agnostic XML format. It does not conform to any formal automotive data standard.

### Major Standards Compared

| Standard | Compatible? | Notes |
|----------|-------------|-------|
| **STAR XML** (AIAG/NADA) | No | Completely different structure — uses complex envelopes, namespaces, typed sub-elements, and different field naming conventions (`ModelYear`, `MakeString`, `VehicleStockNumber`, etc.) |
| **IDS DMS Export** | Partial | The original sample (`Web_Inventory_999.xml`) is an IDS export. Field names like `designation`, `brand`, `lot_location_code` are IDS-specific. The plugin was originally built around IDS. |
| **ACES / PIES** | No | Wrong domain — these are aftermarket parts catalog standards, not vehicle inventory |
| **ADF/XML** | No | Wrong domain — used for sales leads, not inventory |
| **CDK / Reynolds & Reynolds / DealerSocket** | No | Proprietary DMS formats, not implemented |

### STAR XML Specifics

STAR XML is the dominant standard for dealer data exchange in North America. It is fundamentally incompatible because:
- Uses `<StarEnvelope>` with sender/receiver/header metadata
- Has strict namespace declarations and schema versioning
- Field names differ entirely: `ModelYear`, `MakeString`, `OdometerReading`, etc.
- Deeply nested structure vs. this plugin's flat 2-level structure

---

## Non-IDS XML Compatibility

### What the parser actually does

```php
foreach($xml->children() as $child)      // level 1: each unit (any tag name)
{
    foreach($child as $grand_child)       // level 2: each field inside the unit
    {
        $unit[$grand_child->getName()] = strip_tags($grand_child->asXML());
    }
}
```

The parser is flexible — it ignores root and unit tag names entirely.

### Compatibility Matrix

| XML Format | Works? | Notes |
|------------|--------|-------|
| Any flat 2-level XML with `stock_number` | Yes | Works out of the box |
| Flat XML with different field names | Yes | Use field mapping in Settings |
| Flat XML without `stock_number` | No | Vehicles are skipped entirely |
| Nested XML (e.g., STAR XML) | No | Needs XSLT/preprocessing first |
| XML with data stored in attributes | No | Attributes are ignored |

### Hard Requirements

1. **Exactly 2 levels deep (flat structure)**
   - Root → Unit → Field only
   - Any deeper nesting is silently ignored:
   ```xml
   <!-- Will NOT work -->
   <Vehicle>
     <Engine>
       <Cylinders>6</Cylinders>  <!-- ignored, too deep -->
     </Engine>
   </Vehicle>
   ```

2. **Must have a `stock_number` field**
   - Used as the unique key for insert-or-update logic
   - If missing, the entire vehicle is skipped with an error log entry
   - Field mapping does NOT solve this — the source field must be named `stock_number`

3. **Field values must be text content, not attributes**
   ```xml
   <!-- attribute "currency" is lost -->
   <price currency="USD">25000</price>
   ```

### Using Field Mapping for Non-Standard Field Names

The Settings page allows mapping source XML field names to target meta field names:

| Your XML field | Map to |
|----------------|--------|
| `<make>` | `manufacturer` |
| `<asking_price>` | `special_web_price` |
| `<odometer>` | `mileage` |

This remaps where data is stored but does **not** resolve the `stock_number` requirement or depth limitation.

### Integrating Complex/Standard Formats

For formats like STAR XML or complex DMS exports, an intermediate transformation step is required before the plugin can consume the data:

- **XSLT stylesheet** to flatten the source XML into the plugin's 2-level structure
- **Custom preprocessor script** that transforms and re-saves the feed file
- The transformed output must include a `stock_number` field

---

## Settings

| Setting | Description | Default |
|---------|-------------|---------|
| XML File Path / URL | Local path or HTTP(S) URL to the feed | (empty) |
| Import Frequency | How often WP Cron runs the import | Every 10 minutes |
| Vehicle Page Title Template | Token-based template, e.g. `{manufacturer} {brand}` | `{manufacturer} {brand}` |
| Vehicle Description Template | Token-based template for post content | `{designation} {manufacturer} {brand} {model} {model_year}` |
| Field Mappings | Map XML fields to WordPress meta keys | All fields imported as-is |

### Template Tokens

Any XML field name wrapped in `{}` can be used as a token in title/content templates:

```
{manufacturer} {brand} {model_year}  →  Toyota Camry 2024
```

---

## Admin UI

- **Settings page:** WordPress Settings → Automotive Inventory Importer
- **Vehicle edit screen:** Meta box showing all imported fields (editable)
- **Admin notices:** Activation notice, import success/error feedback
- **Log file:** Written to `wp-content/uploads/automotive-feed-import/import-log.txt`

---

## Post Type

- **Slug:** `vehicles`
- **Archive:** `/vehicles/`
- **Supports:** title, editor, thumbnail, custom-fields
- **Menu icon:** `dashicons-car`
- **Menu position:** 5 (below Posts)
