=== AuctionForge ===
Contributors: SmoothByte IT
Tags: auctions, bidding, auction house
Requires at least: 7.2
Stable tag: 3.7.1.15

== Changelog ==

= 3.7.1.15 =
* **Cache now clears when a catalog is published or expanded.** Populating an auction's catalog imports its lots, which purged each lot page and its parent catalog page but NOT the template-rendered auction *listing* pages (home / archive / house pages). An auction that had just gained its first lots kept showing "Catalog available soon" on cached listings until the cache TTL expired. Importing a brand-new lot now also purges the listings -- coalesced into a single full purge per sync on shutdown (no per-lot thrash); plain lot updates are unaffected.

= 3.7.1.14 =
* **Cache now clears when an auction changes state (upcoming→live→ended).** Auction state transitions are time-based and arrive as `auction_state` term-meta writes (the `bp_auto_close` cron, SafetySync, the import pipeline) — which fire `updated_term_meta` but not `edited_<taxonomy>`, so the existing purge hooks never saw them and a finished auction kept showing "Enter Live Auction" / stayed in the upcoming list until the cache TTL expired. `CachePurge` now also hooks `added/updated_term_meta` for `auction_state` on auction terms and purges the listings on any state change.
* **nginx full-purge is now host-scoped.** On a shared server the FastCGI cache directory is used by every site, so a full purge (auction-level change) used to wipe unrelated sites' caches too. `NginxCacheSupport::purgeAll()` now parses each cache file's stored KEY and deletes only entries belonging to the current site's host.

= 3.7.1.13 =
* **nginx FastCGI/proxy cache purge on catalog & lot changes.** Sites fronted by nginx `fastcgi_cache` (micro-caching) now purge the same URLs already sent to Cloudflare and LiteSpeed, so catalog and item pages refresh on sync instead of serving a stale cached copy. Opt-in per site and completely inert otherwise, via a new `NginxCacheSupport` layer in `CachePurge`. Configure with `AF_NGINX_PURGE_URL` / `AF_NGINX_PURGE_METHOD` (the `ngx_cache_purge` module), or `AF_NGINX_CACHE_DIR` / `AF_NGINX_CACHE_LEVELS` / `AF_NGINX_CACHE_KEY` (direct cache-file deletion), or simply activate the rtCamp "Nginx Helper" plugin and AuctionForge delegates to it. Constants (wp-config.php) are preferred; matching `af_nginx_*` options also work.

= 3.7.1.12 =
* **Open-invoices banner now honours "Enable My Invoices tab".** The site-wide "This account has open invoices / Pay Now" banner rendered even on sites with the Invoices tab disabled, and its button led to a profile tab that does not exist. The banner (and its unpaid-bills lookups) is now skipped entirely when the tab is off: `BidspiritViews::bp_footer()` emits `window.afBillingTabEnabled` from the same `enable_billing_tab` setting that gates the tab, and `checkUnpaidBillsBanner()` returns immediately when it is false.
* **US auction houses resolve to the US "Catalog" dialect again (Auto mode).** Restores the address-signature detection lost in an earlier merge: US addresses end in "City, ST 12345" with no country name, so the state+ZIP tail was mistaken for an unknown country and resolved to "Catalogue". `Dialect::countryToDialect()` now recognises a US state code + 5-digit ZIP tail (and a bare trailing ZIP with a `$` currency as a secondary signal). Named countries — including Canada and Australia, whose `$` currencies and 4-digit/lettered postcodes do not match — still resolve to "Catalogue".
* **LiteSpeed purges during sync no longer stack admin notices.** Per-lot cache purges call LiteSpeed's `Purge::purge_url()` quietly instead of the public `litespeed_purge_url` action, which enqueued a dismissible "Purge url …" admin notice for every changed lot — hundreds after a full-auction sync. Manual purges elsewhere keep their confirmations; falls back to the action if the LiteSpeed class is unavailable.
* **Sync log no longer records one row per skipped auction.** The import worker logged "  Skipping auction N (excluded or not matched)" for every excluded auction on every run — the dominant source of `af_sync_log` growth on multi-house sites. It now logs a single "Skipped N/M auctions (excluded or not matched)" summary per run.
* **Housekeeping.** Removed stray `.bak` working files that had been shipping inside the plugin tree since 3.7.1.4.

= 3.7.1.11 =
* **"Auction is live" popup on lot pages.** When BidSpirit reports an auction as live, single-lot pages now show the "Auction is live — Enter live auction" popup (linking to the BidSpirit bidding console), exactly as auction catalogue pages already did. Previously a one-lot auction had no live indication anywhere on the site, because its catalogue URL redirects straight to the lot page and only the catalogue code path surfaced the live state.

= 3.7.1.2 =
* **Background sync worker spawn no longer times out under load ("Worker spawn HTTPS failed: cURL error 28").** `SyncQueue::spawnWorker()` triggered the worker via a blocking loopback request with a hard-coded 5s timeout, so whenever the site's own backend was slower than 5s the spawn aborted as a hard error and raised a sync alert even though the site was up. The timeout is now **15s by default** (overridable via the `AUCTIONFORGE_WORKER_SPAWN_TIMEOUT` constant or `auctionforge_worker_spawn_timeout` filter), the `127.0.0.1` loopback now uses the site's own scheme (avoiding an http→https redirect that forced the slower fallback), and a final non-blocking best-effort request now starts the worker when the backend is merely slow — logged as a warning rather than an error, with the hourly SafetySync cron as backstop. No schema/config change; healthy hosts behave exactly as before.

= 3.7.1.1 =
* **Active uptime monitoring (Kuma keyword health marker).** The keepalive mu-plugin now emits an invisible `<!-- af-health:ok -->` marker on every rendered front-end page (via `wp_head`/`wp_footer`). This lets Uptime Kuma verify the site is genuinely serving WordPress by pulling the homepage and asserting the marker is present — replacing the unreliable push-heartbeat model, which measured WP-Cron liveness rather than real availability and routinely false-flagged perfectly healthy sites as down. The marker lives in the mu-plugin, so it survives AuctionForge being deactivated or mid-update. Bundled keepalive bumped to 1.3.0 (auto-reinstalls on update); the legacy push heartbeat is retained this release for a safe transition.

= 3.7.0.43 =
* **Submission "Need help?" contact is now per-site.** The vehicle-submission help panel previously shipped a single hardcoded email/phone, so every site showed the same (wrong) contact regardless of tenant. It now reads the auction house's email and phone from the site's stored business details (SEO & AEO Optimizer LocalBusiness: `local_email` / `local_phone`), with `apply_filters('auctionforge_help_email')` / `apply_filters('auctionforge_help_phone')` overrides for other sources, and a neutral fallback that hides a row — or the whole block — when no value is set.

= 3.7.0.42 =
* **Submission form markup & content fixes (SEO).** The vehicle-submission templates rendered in the site footer on every page used `<h1>` headings ("Submit your vehicle for auction", "Detail received successfully"), producing multiple H1s in the page source. These are now `<h2>`, leaving a single H1 per page. Replaced the shipped Lorem-ipsum placeholder copy and the dummy "Need help?" contact details (`support@domain.com` / `+3265464325`) with real, production-appropriate text.

= 3.7.0.41 =
* **No more duplicate auction listings** — A brand-new auction could be created twice in WordPress when two syncs ran at the same moment (e.g. a bulk re-sync overlapping a catalogue webhook), each creating its own `auction_number` term before the other committed. The auction then appeared twice and its lots were split across the two copies. `Auction::save()` now serialises term creation per auction with an advisory lock and re-checks authoritatively against the database before inserting, so an existing auction is updated in place instead of duplicated. Complements the existing per-auction catalogue-sync lock that already prevents duplicate lot posts.

= 3.7.0.40 =
* **Lot countdown shows minutes** — The "begins to close" countdown on lot pages now ticks live and shows days/hours/minutes (and seconds in the final minute), so a lot less than an hour from closing no longer reads "0 days and 0 hours". Falls back safely to the previous display on stale-cached pages.

= 3.5.0.6 =
* **Bid Event Tracking** — All successful bids (regular, catalog, pre-sale buyout, post-sale purchase) are now recorded in the user tracking system with `event_type: bid`, capturing the bidder's email, IP, device fingerprint and full browser identity.
* **Self-Healing Database Schema** — Auto-detects and adds any missing tracking table columns on version upgrade.

= 3.5.0.5 =
* **Self-Healing Database Schema** — The plugin now auto-detects and adds any missing tracking table columns on version upgrade, ensuring sites running older database schemas seamlessly migrate without manual SQL intervention.

= 3.5.0.4 =
* **API Key Auto-Healing** — The WordPress plugin now seamlessly self-registers a fresh API Key when WPDeploy returns an `api_key_collision` quarantine blocker. This fully automates the security handover when deploying exact database clones to testing or proxy staging servers without showing ominous red warning cards to developers.

= 3.5.0.3 =
* **API Key Collision Defense** — Implemented an strict identity verification system to prevent cloned testing sites from polluting the central WPDeploy tracking network.
* **Network-Level Quarantine** — Central API dynamically extracts and strictly validates the incoming payload domain against the registered API Key domain, forcefully blocking mismatched traffic (HTTP 403).
* **Local Critical Alert Banner** — Added a persistent crimson warning banner in the WordPress admin panel that intercepts `api_key_collision` errors, directly instructing developers to update cloned keys.

= 3.5.0.2 =
* **Modal Trigger Hotfix** — Restructured internal UI rendering priority to gracefully deploy the inline Modal triggers inside custom IP log view without colliding with cached `z-index` stacks.

= 3.5.0.1 =
* **Hotfix:** Added automatic database schema updater for WPDeploy silent plugin upgrades to prevent column mismatch crashes on `wp_auctionforge_user_tracking`.

= 3.5.0.0 =
* **Full-Spectrum Device Fingerprinting** — Expanded the User Tracking system with 9 new forensic identifiers.
* WebRTC Local IP discovery exposes true internal network addresses even behind VPNs.
* Math Precision Fingerprint detects CPU architecture differences (Intel vs AMD vs Apple Silicon).
* Speech Synthesis voice enumeration and Media Device counting for unique hardware profiling.
* Battery API, Connection Profile, Color Gamut/HDR, and Accessibility preference tracking.
* Form Fill Timing measurement with automatic bot detection flag (<500ms = suspected bot).
* Async collection pipeline fires identifiers in background on page load for zero-latency capture.
* Fingerprint hash upgraded from fp2 to fp3 generation incorporating all new signals.
* Admin dashboard tooltip now shows dynamic identifier count per user with BOT? warning badge.

= 3.4.0.0 =
* **Sync Architecture Expansion** — Fully unified the WPDeploy remote console architecture matching identical features of native plugin.
* Standardized REST API endpoints including adding missing `/sync/auctions` route to managed instances.
* Optimized Sync Dashboard with queue controls, 5 active KPI gauges, and real-time streaming console.
* Resolved proxy JSON crash issues caused by HTML fallback responses on child instances lacking full endpoint routing.

= 3.2.9.2 =
* **Timed Auction Fixes** — Corrected a boolean check on the main upcoming/archive views that improperly hid the Timed Auction badge for catalog pages.

= 3.2.9.1 =
* **Timed Auction Enhancements** — Added a new WP-Admin setting "Change text to 'Auction will close in'" that updates the countdown prompt exclusively for timed/online auctions from "The auction will start in / Live bidding starts in" to "The auction will close in / Auction will close in" across single lot pages and wide upcoming auction shortcodes.

= 3.2.9.0 =
* **Billing & Invoices Polish** — Corrected front-end profile invoice ID tracking.
* Restructured data payloads feeding into `dompdf` generator to display accurate payment statuses rather than cached API defaults.
* Conditionally hid payment instructions on downloaded invoice files when the bill is fully paid.
* Changed "Invoice No" textual display to "Bidder No" on document output.

= 3.2.8.0 =
* **Billing & Invoices PDF Generation** — Implemented server-side generation using `dompdf` allowing users to directly download their exact HTML Bidspirit invoice locally via secure WordPress endpoints.
* Added native UI handling for `PAYMENT_IN_PROGRESS` invoice statuses correctly displaying "In Progress" with a "Resume" action button within the My Invoices interface.

= 3.2.7.0 =
* **Billing & Invoices Integration** — Added "My Invoices" tab to the user profile area.
* Logged-in users can now view their Paid and Unpaid invoices fetched dynamically from Bidspirit.
* New admin toggle under Bidspirit Options to enable or disable the billing tab.
* Unpaid bills include a direct "Pay Now" link.

= 3.2.4 =
* **Sync worker hang fix** — Sync workers were hanging indefinitely at the InsertLotsBS stage because third-party plugins (Smush Pro, SmartCrawl SEO, WPMU DEV) hooked into `wp_insert_post` and made blocking external HTTP calls for every lot. Added `WP_IMPORTING` constant and a `pre_http_request` filter to block all non-essential outbound HTTP during the batch post-insertion phase. Loopback and BidSpirit API calls are still allowed.
* **Stuck staging row recovery** — When workers were force-killed mid-sync, staging rows in `import_history` were left with `syncstart=1`, making them permanently invisible to subsequent sync runs. Workers now operate in an environment where this is mitigated by the faster completion times.

= 3.2.2 =
* **Full Sync discovery fix** — Full Sync now discovers auctions from BidSpirit API before syncing, fixing the issue where freshly deployed sites found 0 auctions.

= 3.2.0 =
* **Archive Sync** — New button on admin Sync Status page to re-sync all past (ARCHIVED/ENDED) auctions. Past auctions now appear in the dropdown.
* **Sync Tasks v3** — Admin task cards now use the v3 queue system. Old importData/importBidSpirit tasks replaced with queue-based Sync Active/Archived buttons.
* **How It Works guide** — Rewritten for v3 webhook-first architecture with job types, queue mechanics, cron setup, and troubleshooting.
* **Dual-write removed** — Legacy webhook handlers removed; all sync now goes through the v3 queue exclusively.
* **ITEMS_UPDATED fix** — Individual lot edits on BidSpirit now trigger real-time sync (auctionId extraction from nested payload).
* **ItemUpdateWorker fix** — Now processes staged data into WP posts + bp_meta_data via InsertLotsBS (was only staging).
* **Worker spawn fix** — HTTP loopback uses 127.0.0.1 with Host header to avoid nginx vhost routing issues.
* **API token** — Plugin expects `AUCTIONFORGE_API_TOKEN` constant in wp-config.php.
* DB version: 22 → 23

= 3.0.0 =

### New Feature: Webhook-First Sync Architecture (Sync v3)
- **Webhook-driven sync** — BidSpirit webhooks now enqueue jobs into a dedicated queue table (`af_sync_queue`) instead of relying solely on polling cron tasks. Data flows from webhook → queue → background worker → WordPress posts.
- **Job Queue System** — New `af_sync_queue` table with priority-based FIFO processing, automatic deduplication by auction_id + job_type, and atomic job claiming to prevent race conditions.
- **Background Worker** (`syncWorker.php`) — Async CLI process spawned by webhooks or the safety cron. Claims and processes queued jobs with a configurable timeout (default 240s). Handles catalog_sync, item_update, full_sync, day_ended, and archive_sync job types.
- **Hourly Safety Net** (`syncSafety.php`) — Replaces the old per-minute importData and hourly importBidSpirit cron tasks with a single hourly cron that: resets stuck jobs, spawns workers for pending jobs, runs a 24-hour health check (auto-enqueues full sync if no webhooks received), and purges old data.
- **Real-time Live Console** — New dark-themed terminal console on the Sync Status admin page. Polls `af_sync_log` every 1.5s showing timestamped, color-coded log entries from webhooks, workers, queue operations, and the safety cron. Supports pause, clear, and auto-scroll.
- **Queue Status Dashboard** — New card on Sync Status page showing pending/processing/completed/failed/skipped counts, recent jobs table, worker status badge, and action buttons (Full Sync, Sync Selected Auction, Spawn Worker).
- **Dual-write mode** — Webhooks enqueue jobs AND still run the legacy handlers during transition. Once verified, legacy handlers can be removed cleanly.
- **WP-Cron safety hook** (`auctionforge_sync_safety`) — Always-active hourly WP-Cron event that resets stuck jobs and spawns workers, independent of the external cron system.
- **Cron installer v3** (`setup.sh`) — Updated task definitions: removed `importData` (every minute) and `importBidSpirit` (hourly), added `syncSafety` (hourly at :10). New `migrate` command for interactive v2→v3 crontab transition.
- **cURL timeout** — BidSpiritRequest now has a 30-second cURL timeout (was unlimited) to prevent hung connections blocking the sync pipeline.

### New Files:
- `inc/sync/SyncQueue.php` — Queue model with enqueue, claim, complete, fail, skip, reset, spawn, purge
- `inc/sync/SyncLogger.php` — Real-time logging with level filtering and incremental polling
- `inc/sync/CatalogSyncWorker.php` — Processes catalog/full/day-ended sync jobs
- `inc/sync/ItemUpdateWorker.php` — Processes individual item update jobs
- `crontasks/syncWorker.php` — CLI background worker process
- `crontasks/syncSafety.php` — CLI hourly safety net process

### New DB Tables:
- `af_sync_queue` — Job queue (status, priority, source, attempts, worker PID, timing)
- `af_sync_log` — Real-time log entries (context, level, auction_id, job_id)

### Technical Details:
- DB version bumped from 20 to 22
- 7 new constants: AUCTIONFORGE_SYNC_WORKER_TIMEOUT, AUCTIONFORGE_SYNC_STALE_JOB, AUCTIONFORGE_SYNC_HEALTH_CHECK, AUCTIONFORGE_SYNC_LOG_RETENTION, AUCTIONFORGE_SYNC_QUEUE_RETENTION, AUCTIONFORGE_CURL_TIMEOUT, AUCTIONFORGE_PHP_BINARY
- 3 new AJAX handlers: auctionforge_sync_log_poll, auctionforge_sync_queue_status, auctionforge_sync_enqueue
- Net cron change: 5 entries → 4 entries, ~62 PHP executions/hour → 1

= 2.7.1.2 =

### Fixes:
- Added missing `vatAndCommission()` function in `loadBid()` — the sales tax display on single lot pages was never being rendered because the code to call `loadTemplate` for `vat-and-commission-template` was missing from `app.js`. Also added missing `setAuctionItemInfo()` call.

= 2.7.1.1 =

### Fixes:
- 2 decimal places now only appear in the bid modal (Your max bid, Total Price) via `showDecimals` flag. Start price, increments list, and other prices show whole numbers as before.

= 2.7.1.0 =

### Fixes:
- Fixed Buyer's Premium value not showing on single lot pages — added missing `auction-commission-field` population in `auctionInfoInit()` from upstream reference.

= 2.7.0.9 =

### Fixes:
- Fixed fatal error during plugin install/upgrade: `class-stats-database.php` require failure. Added `file_exists` guard in `AF_Stats_Init::activate()` and plugin-specific guard in `upgrader_process_complete` hook to prevent running upgrade logic for unrelated plugin updates.

= 2.7.0.8 =

### Fixes:
- Synced `formattedPrice()` across both `app.js` and `app.min.js` — added second currency support, better null/NaN handling, and always 2 decimal places on all prices. Fixes sites where minification plugins may load `app.min.js` instead of `app.js`.

= 2.7.0.7 =

### Fixes:
- All prices now display with 2 decimal places (e.g. $10.00 instead of $10) via `formattedPrice()` using `toLocaleString` with `minimumFractionDigits: 2`.

= 2.7.0.6 =

### Fixes:
- Added missing `estimatedPrice`, `content`, and `isShop` template variables to widget and shortcode `lot-content-template` calls, preventing potential ReferenceErrors on catalogue pages with ended auctions or shop items.

= 2.7.0.5 =

### Fixes:
- Fixed Stripe payment form not visible in Add Payment Method modal — `#stripePaymentElement` had `hidden` class that was never removed. Now unhides form on Stripe `ready` event and re-hides on modal close.

= 2.7.0.4 =

### Fixes:
- Fixed `bidspiritApi.getAuctionSettingsData is not a function` error in getFullPriceInfo — use local auctionSettingsData variable instead of non-existent API method.

= 2.7.0.3 =

### Fixes:
- Fixed `fullPriceInfo is not defined` ReferenceError that prevented bid confirmation modal from opening on single lot pages and catalogue pages.
- Added missing `getFullPriceInfo()`, `getCommissonInfoForPrice()`, and `roundToCents()` functions ported from upstream.
- All three bid submission paths (submitBid, submitBidCatalog, submitBidCatalog3) now correctly pass fullPriceInfo to the modal-bid-template.

= 2.7.0.0 =

### New Features: Advanced Lot Analytics
- **Conversion Tracking** — View-to-bid ratio table showing lot views, catalogue/external clicks, favorites, shares, bid status, and sold price with sell-through rate summary cards
- **Peak Viewing Times** — Hourly bar chart showing when lots get the most views (last 30 days) with peak hour identification
- **Pre-Sale vs Live Comparison** — Per-auction breakdown of views before auction day vs during/after, with pre-sale percentage
- **Category Performance** — Analytics grouped by lot category: views, lots, favorites, sold count, average views per lot
- **Share Analytics** — Track shares by channel (Facebook, Twitter, WhatsApp, Email, Pinterest, Copy Link) with per-channel badges and most-shared lots table
- **Search → View Funnel** — Correlates internal search queries with subsequent lot page views to show which searches lead to browsing
- **Click-Through Tracking** — Distinguishes catalogue clicks (user came from auction catalogue) vs external clicks (direct/search/referral)
- **CSV Export** — One-click export of all lot analytics data, filterable by catalogue
- **Hot Lot Badge** — Automatic "🔥 Popular" badge on catalogue page thumbnails for lots exceeding view threshold (default: 5 views)
- All new panels respect the catalogue filter dropdown
- New DB table: af_lot_shares (per-channel share events)
- New columns: catalogue_clicks, external_clicks, share_count on af_lot_analytics
- DB version bumped to 20

= 2.6.3.0 =

### Fixes:
- View counter now shows on lot pages even with 0 views
- Fixed backfill and trending queries failing on URLs with trailing slashes

= 2.6.2.0 =

### Fixes:
- Fixed 404 errors on auction/lot pages after DB version update by flushing rewrite rules automatically

= 2.6.1.0 =

### Fixes:
- Renamed shortcodes to use bp_ prefix for consistency: [bp_popular_lots], [bp_most_favorited], [bp_trending_lots]

= 2.6.0.0 =

### New Feature: Lot Analytics
- Added comprehensive lot view and favorite tracking system
- Two new settings in AuctionForge > Settings (both disabled by default):
  - **Enable Lot Analytics** — master toggle for the entire tracking system
  - **Show View Counter on Lots** — display a public view count on each lot page
- New admin dashboard tab: **Lot Analytics** (under Site Statistics) with:
  - Auction Performance comparison table
  - Most Viewed Lots (all time)
  - Most Favorited Lots
  - Trending Lots (last 7 days)
  - Backfill from existing pageview data button
- Local favorites tracking mirrors BidSpirit favorites for analytics
- Three new shortcodes for displaying popular lots:
  -  — most viewed lots grid
  -  — most favorited lots grid
  -  — trending lots (configurable time window)
- All shortcodes support limit, columns, auction_id, and period filtering
- New DB tables: af_lot_analytics, af_lot_favorites (DB version 19)

= 2.5.9.0 =

### Improvements:
- Redesigned Recently Viewed items as square card grid (rows/columns) instead of horizontal list.
- Changed lot thumbnail to contain (show full image) instead of cover (crop to fill).

= 2.5.8.0 =

### Fixes:
- Fixed Recently Viewed cloned image thumbnails using non-existent resize prefix. Now uses raw image filename for reliable CDN loading.

= 2.5.7.0 =

### Fixes:
- Fixed Recently Viewed thumbnail URLs — now builds correct BidSpirit CDN URLs for both cloned (Fastly) and non-cloned (Cloudinary) images instead of broken relative paths.

= 2.5.6.0 =

### Fixes:
- Fixed placeholder image fallback path still referencing old uco-auctions directory.
- Added background color for empty thumbnail containers in Recently Viewed.

= 2.5.5.0 =

### Improvements:
- Removed PAST/Upcoming badges from Recently Viewed items display.
- Added lot thumbnail images to Recently Viewed items with proper card layout.

= 2.5.4.0 =

### Fixes:
- Fixed item variable not being passed to auctionIsLive-template (was lost during previous file edits).

= 2.5.3.0 =

### Fixes:
- Fixed `item is not defined` in `displayBidFormData` — removed stray `item: item` from house-info-template call where item variable does not exist in scope.

= 2.5.2.0 =

### Fixes:
- Fixed `item is not defined` JavaScript error in `auctionIsLive-template` on single lot pages.
- Fixed statistics table auto-creation running on frontend requests (restricted to admin only).

= 2.5.1.0 =

### Fixes:
- Fixed `hideleadingBidSection is not defined` JavaScript error on single lot pages.
- Fixed statistics database tables not auto-creating on plugin update (only activated on fresh install).
- Added self-healing table creation on `plugins_loaded` for sites that update without re-activating.
- Cleaned up duplicate `AF_Stats_Init::activate()` calls in DB update function.
- Bumped DB version to 18.

= 2.5.0.0 =

### New Features:
- **Site Statistics System** — Full website analytics built into the plugin admin (Lots → Site Statistics).
  - Dashboard with KPI cards: visitors, sessions, pageviews, bounce rate, avg duration, pages per session.
  - Period comparison: current vs previous period with percentage change indicators.
  - Traffic over time line chart (pageviews, visitors, sessions).
  - Traffic channels doughnut chart (organic search, direct, referral, social, email, paid).
  - Hourly distribution bar chart.
  - Device type pie chart (desktop, mobile, tablet).
  - Top Pages tab with views, unique visitors, avg time on page, search, pagination, CSV export.
  - Referrers tab with traffic channel badges, sessions, bounce rate, avg duration, CSV export.
  - Countries tab with horizontal bar chart and visitor/pageview counts.
  - Technology tab with browser, OS, device breakdown and screen resolutions.
  - Searches tab tracking internal WordPress and auction search queries.
  - 404 Errors tab tracking broken URLs with hit counts and referrers.
  - Real-Time visitors view (last 5 minutes, auto-refreshes every 10 seconds).
  - Settings tab: enable/disable tracking, exclude IPs and roles, IP anonymization (GDPR), data retention.
  - Date range picker with presets (7, 14, 30, 90, 365 days) and custom range.
  - Lightweight frontend tracker (~3KB JS) with session management, heartbeat, and beacon API.
  - GeoIP country/city lookup via ip-api.com with 24-hour cache.
  - Bot detection (30+ crawler patterns filtered).
  - UTM parameter tracking (source, medium, campaign, term, content).
  - Traffic channel auto-classification.
  - Outbound link click tracking.
  - Time-on-page tracking via 30-second heartbeat + page unload beacon.
  - Daily cron for automatic data retention purge.
- **Recently Viewed Items** — New profile page tab showing the last 20 viewed lots per user.
  - Admin setting to enable/disable (Lots → Settings → Enable user viewing history).
  - Tracks lot views with timestamp, stores in custom DB table.
  - Clear history button for users.
  - Disabled by default.

### Fixes:
- Fixed `settings is not defined` JavaScript error on auction catalog and single lot pages.
- Fixed `postAuctionSaleOpened is not defined` JavaScript error on auction pages.
- Fixed missing `vendor.min.css` and `password-validation.min.css` (404 errors).
- Added missing template variables to all `loadTemplate` calls for `lot-content-template`, `leadingBid-template`.

= 2.4.4.0 =

### Fixes:
- Fixed the display of purchase prices on shop pages for unsold items. Items with a buyout price now correctly show the "Purchase Price" in both ended and active auction states.

= 2.3.5 =

### New Features:
- Added the ability to create a menu item that opens a modal login window. (`[href="#bp-profile"]`)
- Prices are now displayed with a secondary currency.
- Added an option to display prices including taxes.

### Improvements:
- Login and registration pages no longer leave users on the default welcome page after authentication.
- Updated German localization.
- Added Dutch localization.
- Optimized the synchronization process for auction houses with a large number of auctions.
- Updated the user manual. Added a section with available shortcodes.

### Fixes:
- Fixed a synchronization issue when default and secondary language settings were incorrect in the plugin.
- Fixed broken content in the *Make an inquiry about this item* link when special characters were present in the lot title.
- Fixed display of current bids for lots depending on the auction house settings.
- Fixed display of current bids for lots that are loaded when scrolling the page, if the "Enable pagination" option is disabled.
- Fixed handling of lots that were removed from the auction.
- Fixed bid display on the catalog page when the *enablePrebidsUnderStartPrice* option is enabled.