# Changelog

All notable changes to BW Map Magnet are documented here.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.5.2] - 2026-05-20

### Fixed
- Hovered marker now correctly lifts above neighbouring markers in clustered areas (Grace Bay had several pins overlapping the hovered one, making it look buried even though it was scaled up and the others were faded). Leaflet stacks markers via `z-index` on the outer `.leaflet-marker-icon` wrapper which CSS rules on our inner divIcon HTML can't reach; switched to `marker.setZIndexOffset(900)` on focus and `0` on reset. The central marker continues to sit at +1000, so the focused pin lifts above peers but never over the central.

## [1.5.1] - 2026-05-20

### Changed
- **"Custom" central marker style now means custom image, not custom icon.** The icon library belongs on per-category markers; for the single central marker the right tool is "upload a specific image." The settings page now offers a WP media-library picker (with preview + Replace / Remove buttons) when Marker style = Custom. Removed the now-obsolete icon-library grid and `central_icon` setting.
- **Image-mode markers (Logo and Custom image) now use the accent color as the background**, not a hard-coded white. This makes white logos legible on a dark accent and dark logos legible on a light accent. The accent-color setting label changed from "Marker color" to "Marker accent color" to reflect this.
- Logo and Custom-image modes now share the same rendering path (`.bw-mm-marker--image`) and same 44 × 44 size; they're functionally the same marker with different image sources.
- Replaced the JSON config field `logoUrl` with `imageUrl` (used for both Logo and Custom-image modes). Server-side rendering resolves the URL from either the site logo (`get_theme_mod('custom_logo')`) or the chosen attachment ID.

## [1.5.0] - 2026-05-20

### Added
- **Central marker style — Logo / Pin / Custom.** The full icon library on the settings page was overkill for a single "home" pin; replaced with a three-way radio:
  - **Logo** (default) — uses the WordPress site logo from Customizer → Site Identity. Rendered as a white round badge with a coloured border, the logo image filling the inside. Falls back to "Pin" automatically if no logo is set, with an inline notice on the settings screen pointing the user to the Customizer.
  - **Pin** — the simple map-pin glyph from the icon library, white on the configured accent colour.
  - **Custom** — reveals the full icon-library grid, identical to the per-category picker. Same coloured-circle styling as Pin mode.
- New `central_icon_mode` setting (default `logo`) plus `logoUrl` resolution server-side via `get_theme_mod('custom_logo')` → `wp_get_attachment_image_url($id, 'medium')`. The grid is hidden until Custom is selected (handled in JS).

### Changed
- **Fresh-install defaults shifted to Bowden Works.** `central_lat` 49.688234, `central_lng` -124.992516, `central_title` "Bowden Works" — so the central-location preview map shows something useful on first install instead of (0,0) in the Atlantic. Existing installs keep their saved values; only new sites see the new defaults.
- Central marker dimensions bump from 40×40 to 44×44 in Logo mode, with white background + 3 px coloured border + 3 px padding so the logo image breathes.
- The settings-page "Marker icon" field renamed to "Custom icon" and shows a description making clear it only applies when Marker style = Custom.

## [1.4.0] - 2026-05-20

### Added
- **Central focus location.** Set a single "home" / "anchor" pin (e.g. the resort) in `Map Magnet → Settings` → Central focus location. When enabled:
  - The central marker is **always shown** on every map and never fades.
  - **Distinct visual styling** — bigger (40×40), thicker border, glowing ring, configurable icon and color (defaults: amber `#f59e0b` + `landmark` icon).
  - Hovering an item now **fits bounds to include both the central pin and the hovered item**, so visitors can see distance / direction at a glance. Per-item `focusZoom` caps how close the pair can go.
  - All **other markers fade out** on hover (opacity 0.18); only the hovered item and the central remain at full opacity.
  - Item popups gain a **distance line** ("0.8 km from The Regent Grand") and a **"Get directions" button** that opens Google Maps directions from the central pin to the item.
  - Distance unit configurable (km or miles). Below 1 unit, distance falls back to metres or feet for readability.
  - The central pin is included in the idle fit-bounds calculation so it's always on screen.
- Settings page expanded with a full **central-location editor**: enable toggle, label, lat/lng inputs, **"Fetch by Google Maps URL"** field (re-uses the existing AJAX endpoint), an interactive Leaflet preview map (drag-to-adjust), icon picker grid (same library as taxonomy icons), WP color picker, distance toggle/unit, and a customisable "Get directions" button label.

### Changed
- Initial / idle fit-bounds now includes the central pin (when one is set), so the central is always visible at rest.
- Setting `central_enabled = false` (the default) preserves 1.3 behaviour exactly — no central marker, no fade-out, no popup additions.

## [1.3.0] - 2026-05-20

### Added
- New **Map Magnet → Settings** admin page with two site-wide options:
  - **Default hover zoom level** (6–19, default 16). The fall-through default for every shortcode and block on the site.
  - **Animation duration (seconds)** (0.1–5.0, default 1.5). How long the fly-to and zoom-out transitions take. Previously hard-coded at 0.6 s — many users found it jarring.
- New **per-item "Override hover zoom level"** field on every Map Item edit screen. Stored as `_bw_map_focus_zoom` post meta. Use a higher number for tight spots (a specific restaurant entrance) or lower for spread-out places (a kilometre-long beach). Empty = use the instance/site default.
- Block inspector "Hover zoom level" range now extends to 19 (was 18) and seeds from the site default on fresh block insert (via `wp_localize_script`).

### Changed
- Default animation duration is now **1.5 s instead of 0.6 s** — calmer, less jarring on hover-driven UIs. Override on the Settings page.
- Settings, shortcode, and block now share a single cascade: per-item meta → shortcode/block attribute → site setting → hard-coded fallback (zoom 16, duration 1.5 s).

## [1.2.2] - 2026-05-20

### Fixed
- Map popup titles were rendering raw HTML entities like `Smith&#8217;s Reef` because the title arrived already entitised from WordPress's `wptexturize` filter and the frontend `escapeHtml()` then re-escaped the leading `&` to `&amp;`, defeating the entity. Now the shortcode renderer runs `html_entity_decode()` on title and excerpt before serialising to JSON, so the JS escapes a raw character into a fresh entity on insertion. The list column was unaffected (it uses `esc_html()` which doesn't double-encode) — fix is for the popups only.

### Changed
- Default zoom level when hovering a list item bumped from 14 (district) to 16 (street). Closer to building-level so a single hover lands you near the entrance. Override per-instance with the `focus_zoom` shortcode attribute or the block's "Hover zoom level" inspector slider.

## [1.2.1] - 2026-05-14

### Fixed
- "Fetch by Google Maps URL" was dropping the pin on the map correctly but writing `NaN` to the Latitude / Longitude inputs, so the location was lost on save. Root cause: the JS `sync()` helper only read `.lat`/`.lng` properties from Leaflet `LatLng` objects, but the new Google Maps fetch path (and the existing manual lat/lng-input handler) called it with a `[lat, lng]` array. Reading `.lat` from an array yields `undefined` → `Number(undefined).toFixed(6)` → `"NaN"`. Added a `normalizeLatLng()` helper that accepts both arrays and `{lat, lng}` objects, and made `sync()` refuse to overwrite the inputs with bad input (returns silently instead of writing `NaN`).
- Same fix also restores manual lat/lng editing — typing into the Latitude or Longitude field and blurring no longer wipes the value via the `change` handler.

## [1.2.0] - 2026-05-14

### Added
- "Fetch by Google Maps URL" field on the Map Item edit screen. Paste any Google Maps share URL (long form, short `maps.app.goo.gl`, or simple `?q=lat,lng`) and click "Fetch location" — the plugin extracts coordinates server-side and drops the pin precisely. Tries the pin-position pattern (`!3d!4d`) first, then map-center (`@LAT,LNG`), then query-string forms. Short URLs are resolved by following the response body for embedded coordinates. Status label reports whether the result came from the pin position or the visible map center (so the user knows whether to drag-adjust).
- AJAX endpoint `wp_ajax_bw_map_magnet_gmaps_lookup` with nonce + `edit_posts` capability check and a strict allowlist of Google host names. Uses `wp_safe_remote_get()` (no internal addresses, no SSRF).
- A friendly Grace Bay default centre when adding a new Map Item without coordinates (was: Cathedral Grove, BC).

### Fixed
- The admin map no longer hijacks the pin when you click on it while reviewing an already-placed marker. Map clicks now only place the pin when no marker exists yet; after that, the marker is only moved by dragging it, editing the lat/lng inputs, or using one of the explicit "Find" / "Fetch by Google Maps URL" actions. This was the source of the "values seem to reset easily when I click away" issue — incidental map clicks were overwriting the placed coordinates.
- The Nominatim "Find" failure message now suggests using the Google Maps URL option, since OSM frequently lacks business listings.

## [1.1.0] - 2026-05-14

### Added
- CSV importer can now download remote `image_url` values and attach them as the post's featured image. Opt-in via a new "Download images and set as featured images" checkbox on the Import / Export screen. The importer uses `download_url()` + `media_handle_sideload()` and sets alt text from the post title. If a download fails for any row, the URL is kept as the fallback `_bw_map_image_url` meta (so the frontend still renders the thumbnail from the remote source).
- Per-row image-download stats are surfaced in the result notice ("Images downloaded: N · Image downloads failed: M") and any failed rows are listed in the error log.
- `set_time_limit( 600 )` is requested up-front during import so larger CSVs with many image downloads don't hit PHP's default 30 s execution limit.

### Fixed
- The sideloader registers a high-priority repair filter on `wp_check_filetype_and_ext` for the duration of each sideload. Some site-wide plugins (notably SVG-upload extensions) intercept this filter at priority 10 and over-blank the result, breaking legitimate JPEG/PNG uploads with "Sorry, you are not allowed to upload this file type." The repair filter detects when upstream filters returned empty data and restores the correct `ext`/`type` based on a content-sniffed MIME, then unhooks itself. Other code paths are unaffected.

## [1.0.0] - 2026-05-14

First stable release. No code changes from `0.3.1` — graduated to `1.0.0` after end-to-end review of the feature set:

- Custom post type + taxonomy for map items with a Leaflet/OSM admin picker.
- `[bw_map_magnet]` shortcode and `bw-map-magnet/map` Gutenberg block (server-rendered) with the same engine.
- Hover-to-fly, click-to-pin, idle fit-bounds, mobile-stacked layout, keyboard-accessible list items.
- Per-category icons (~25 monoline SVGs themed for resort use) and per-category colors (WP color picker).
- Frontend filter chips with icon, name, item count; single-select with "All".
- Image URL override field + featured-image fallback; popups carry thumbnails.
- CSV import / export — exports every item, imports with column alias matching, auto-creates missing categories, validates rows, supports upserts by title.
- Demo seeder for Vancouver Island data (re-runnable; backfills icons/colors/images on existing terms).

## [0.3.1] - 2026-05-13

### Fixed
- Redrew the `bird` icon — the previous Lucide-style paths weren't readable at marker scale. New design is a clear perched-bird silhouette: oval body, triangular beak at the right, wing line, eye dot, and two legs.
- Filter chip hover state was hard to read under some themes. The theme's generic `button:hover` was overriding the chip's white background with a dark fill while the text stayed dark. Hover now explicitly sets a light background (`#f8fafc`) under `.bw-mm-wrap` scope to outrank theme rules, uses `:not(.is-active)` so it doesn't fight the active state, and adds a subtle `filter: brightness(0.92)` on hovering an already-active chip for feedback. Also covers `:focus-visible` for keyboard users.

## [0.3.0] - 2026-05-13

### Added
- CSV import / export. New `Map Magnet → Import / Export` submenu provides:
  - One-click CSV export of every map item (columns: title, category, latitude, longitude, excerpt, content, image_url). UTF-8 with BOM so Excel detects encoding correctly.
  - CSV upload importer with header-row column matching (accepts aliases like `lat`/`lng`/`lon`, `image`, `description`). Required columns: title, latitude, longitude. Missing categories are auto-created; existing categories are matched by slug then name.
  - "Update existing items (match by title)" toggle for upserts; otherwise duplicate-title rows are skipped.
  - Per-row validation with line-numbered error reporting on the result notice.
- Per-category color. New term meta `_bw_map_color` with a WP color picker on the taxonomy add/edit screens. The color is applied to map markers (background), filter chip (active state and hover border), category title underline, item-hover border, and the empty-thumbnail placeholder icon.
- Demo seeder now sets a color on each demo category (Free Outdoor Activities = green, Best Restaurants = burnt orange) and re-seeding backfills colors on older terms.

### Changed
- Redrew 7 SVG icons for better recognisability: `scuba` is now a tank (cylinder + valve), `fishing` is a clearer fish (rounded body, triangular tail), `kayak` is a canoe paddle (T-grip + blade), `spa` is a leaf with central vein, `turtle` is a top-down view with four flippers, `bird` swapped to a Lucide-style perched bird, `fire` swapped to a single-flame Lucide design with inner curl.
- Active marker no longer hard-codes orange — it scales and darkens using the category color via CSS filters, so it stays on-brand.

## [0.2.0] - 2026-05-13

### Added
- Icon library — ~25 monoline SVG icons themed for resort use (beach, palm, snorkel, scuba, boat, fishing, kayak, waves, anchor, restaurant, cocktail, coffee, spa, shopping, tour/compass, turtle, bird, lighthouse, golf, tennis, music, fire pit, landmark, sun).
- Per-category icon picker on the taxonomy add/edit screens. Picked icon shows on map markers, in popups, on the filter chips, and in the term list table.
- Frontend filter UI — pill-style chips above the list with category icon, name, and item count. Click a chip to show only that category; click "All" to show everything. Map bounds re-fit to visible items, list filters in sync.
- `_bw_map_image_url` post meta + admin field — external image URL override that the frontend uses as the item thumbnail (lets authors point at CDN/stock photos without uploading). Falls back to the featured image when blank.
- Image thumbnails inside map popups when an image is set.
- Gutenberg block (`bw-map-magnet/map`) — dynamic, server-rendered with the same engine as the shortcode. Inspector controls for category filter, height, focus zoom, and filter-chips toggle. Live preview in the editor via ServerSideRender.
- Demo seeder now sets:
  - Icons on the two demo categories (`palm` on Free Outdoor Activities, `restaurant` on Best Restaurants).
  - Picsum-seeded image URLs on every demo item (unique consistent photo per item).
- Re-running the seeder upgrades existing items — backfills missing image URLs and category icons.

### Changed
- Markers are now circular icon badges (32×32) rendering the category's chosen icon in white on the brand blue, with the active state turning orange and scaling up.
- Empty-thumbnail placeholder now uses the category icon on a soft blue gradient instead of a plain grey block.

## [0.1.0] - 2026-05-13

### Added
- Custom post type `bw_map_item` for map locations (title, description, featured image, lat/lng).
- Hierarchical taxonomy `bw_map_category` for grouping items (e.g. "Free Outdoor Activities", "Best Restaurants").
- Admin meta box with interactive Leaflet/OpenStreetMap picker — click to set, drag to refine, search a place name via Nominatim geocoding.
- `[bw_map_magnet]` shortcode with `category`, `height`, `zoom`, `focus_zoom`, `limit` attributes.
- Responsive frontend with sticky map and scrollable categorised list.
- Hover-to-zoom interaction: hovering a list item flies the map to that marker; idle state fits all visible items.
- Click-to-pin behaviour: clicking an item opens its popup and keeps focus until clicked again.
- Keyboard accessibility on list items (Enter/Space focus and activate).
- One-click Vancouver Island demo seeder (12 items across two categories) under Map Magnet → Help & Demo Data.
